From d6d5f46baea90e9b8a305a010457ac6d404d8829 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 11 Apr 2019 16:02:38 +0000 Subject: [PATCH 01/33] Update OAuth web template --- lib/pleroma/web/templates/layout/app.html.eex | 45 ++++++++++++--- .../web/templates/o_auth/o_auth/show.html.eex | 57 ++++++++++++++----- 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index 8333bc921..7d2d609d1 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -63,13 +63,14 @@ .scopes-input { display: flex; + flex-direction: column; margin-top: 1em; text-align: left; color: #89898a; } .scopes-input label:first-child { - flex-basis: 40%; + height: 2em; } .scopes { @@ -80,13 +81,22 @@ } .scope { - flex-basis: 100%; display: flex; + flex-basis: 100%; height: 2em; align-items: center; } + .scope:before { + color: #b9b9ba; + content: "✔"; + margin-left: 1em; + margin-right: 1em; + } + [type="checkbox"] + label { + display: none; + cursor: pointer; margin: 0.5em; } @@ -95,10 +105,12 @@ } [type="checkbox"] + label:before { + cursor: pointer; display: inline-block; color: white; background-color: #121a24; border: 4px solid #121a24; + box-shadow: 0px 0px 1px 0 #d8a070; box-sizing: border-box; width: 1.2em; height: 1.2em; @@ -128,7 +140,8 @@ border-radius: 4px; border: none; padding: 10px; - margin-top: 30px; + margin-top: 20px; + margin-bottom: 20px; text-transform: uppercase; font-size: 16px; box-shadow: 0px 0px 2px 0px black, @@ -147,8 +160,9 @@ box-sizing: border-box; width: 100%; background-color: #931014; + border: 1px solid #a06060; + color: #902020; border-radius: 4px; - border: none; padding: 10px; margin-top: 20px; font-weight: 500; @@ -171,12 +185,27 @@ margin-top: 0 } - .scopes-input { - flex-direction: column; + .scope { + flex-basis: 0%; } - .scope { - flex-basis: 50%; + .scope:before { + content: ""; + margin-left: 0em; + margin-right: 1em; + } + + .scope:first-child:before { + margin-left: 1em; + content: "✔"; + } + + .scope:after { + content: ","; + } + + .scope:last-child:after { + content: ""; } } diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 87278e636..c7b4ef792 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -6,26 +6,53 @@ <% end %>

OAuth Authorization

- <%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %> -
- <%= label f, :name, "Name or email" %> - <%= text_input f, :name %> -
-
- <%= label f, :password, "Password" %> - <%= password_input f, :password %> -
-<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f, scope_param: "authorization[scope][]"}) %> +<%= if @params["registration"] in ["true", true] do %> +

This is the first time you visit! Please enter your Pleroma handle.

+

Choose carefully! You won't be able to change this later. You will be able to change your display name, though.

+

Please only use lowercase letters and no special characters

+
+ <%= label f, :nickname, "Pleroma Handle" %> + <%= text_input f, :nickname, placeholder: "lain" %> +
+ <%= hidden_input f, :name, value: @params["name"] %> + <%= hidden_input f, :password, value: @params["password"] %> +
+ +<% else %> +
+ <%= label f, :name, "Username" %> + <%= text_input f, :name %> +
+
+ <%= label f, :password, "Password" %> + <%= password_input f, :password %> +
+ <%= submit "Log In" %> +
+ <%= label f, :scope, "The following permissions will be granted" %> +
+ <%= for scope <- @available_scopes do %> + <%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %> + <%= if scope in @scopes do %> +
+ <%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> + <%= label f, :"scope_#{scope}", String.capitalize(scope) %> + <%= if scope in @scopes && scope do %> + <%= String.capitalize(scope) %> + <% end %> +
+ <% else %> + <%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> + <% end %> + <% end %> +
+
+<% end %> <%= hidden_input f, :client_id, value: @client_id %> <%= hidden_input f, :response_type, value: @response_type %> <%= hidden_input f, :redirect_uri, value: @redirect_uri %> <%= hidden_input f, :state, value: @state %> -<%= submit "Authorize" %> -<% end %> - -<%= if Pleroma.Config.oauth_consumer_enabled?() do %> - <%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %> <% end %> From 9a98f48ec3f438e543a5a621624401bb22a0d44a Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 1 May 2019 12:29:48 -0500 Subject: [PATCH 02/33] Remove incorrect statement about valid characters --- lib/pleroma/web/templates/o_auth/o_auth/show.html.eex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index c7b4ef792..45f2b5cc0 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -11,7 +11,6 @@ <%= if @params["registration"] in ["true", true] do %>

This is the first time you visit! Please enter your Pleroma handle.

Choose carefully! You won't be able to change this later. You will be able to change your display name, though.

-

Please only use lowercase letters and no special characters

<%= label f, :nickname, "Pleroma Handle" %> <%= text_input f, :nickname, placeholder: "lain" %> From eb2963bc43f2cb195c2f19e6081c3faa6375fe4e Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 31 May 2019 14:27:15 +0200 Subject: [PATCH 03/33] User: Add settings store to Info, AccountView This is to provide a generic frontend settings storage mechanism for all kinds of frontends. --- lib/pleroma/user/info.ex | 1 + .../web/mastodon_api/views/account_view.ex | 10 ++++++++++ test/web/mastodon_api/account_view_test.exs | 15 +++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 6397e2737..e6623160d 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -45,6 +45,7 @@ defmodule Pleroma.User.Info do field(:flavour, :string, default: nil) field(:mascot, :map, default: nil) field(:emoji, {:array, :map}, default: []) + field(:pleroma_settings_store, :map, default: %{}) field(:notification_settings, :map, default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b82d3319b..04d485340 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -130,6 +130,7 @@ defp do_render("account.json", %{user: user} = opts) do |> maybe_put_role(user, opts[:for]) |> maybe_put_settings(user, opts[:for], user_info) |> maybe_put_notification_settings(user, opts[:for]) + |> maybe_put_settings_store(user, opts[:for], opts) end defp username_from_nickname(string) when is_binary(string) do @@ -152,6 +153,15 @@ defp maybe_put_settings( defp maybe_put_settings(data, _, _, _), do: data + defp maybe_put_settings_store(data, %User{info: info, id: id}, %User{id: id}, %{ + with_pleroma_settings: true + }) do + data + |> Kernel.put_in([:pleroma, :settings], info.pleroma_settings_store) + end + + defp maybe_put_settings_store(data, _, _, _), do: data + defp maybe_put_role(data, %User{info: %{show_role: true}} = user, _) do data |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin) diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index aaf2261bb..ca73d6581 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -239,4 +239,19 @@ test "represent an embedded relationship" do assert expected == AccountView.render("account.json", %{user: user, for: other_user}) end + + test "returns the settings store if the requesting user is the represented user and it's requested specifically" do + user = insert(:user, %{info: %User.Info{pleroma_settings_store: %{fe: "test"}}}) + + result = + AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true}) + + assert result.pleroma.settings == %{:fe => "test"} + + result = AccountView.render("account.json", %{user: user, with_pleroma_settings: true}) + assert result.pleroma[:settings] == nil + + result = AccountView.render("account.json", %{user: user, for: user}) + assert result.pleroma[:settings] == nil + end end From aaad85c4d908dd14c1d836ebe2a5302cfdfaff2e Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 31 May 2019 14:49:46 +0200 Subject: [PATCH 04/33] AccountView: settings -> settings_store --- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- test/web/mastodon_api/account_view_test.exs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 04d485340..dc32a1525 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -157,7 +157,7 @@ defp maybe_put_settings_store(data, %User{info: info, id: id}, %User{id: id}, %{ with_pleroma_settings: true }) do data - |> Kernel.put_in([:pleroma, :settings], info.pleroma_settings_store) + |> Kernel.put_in([:pleroma, :settings_store], info.pleroma_settings_store) end defp maybe_put_settings_store(data, _, _, _), do: data diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index ca73d6581..5e6f1d00b 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -246,12 +246,12 @@ test "returns the settings store if the requesting user is the represented user result = AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true}) - assert result.pleroma.settings == %{:fe => "test"} + assert result.pleroma.settings_store == %{:fe => "test"} result = AccountView.render("account.json", %{user: user, with_pleroma_settings: true}) - assert result.pleroma[:settings] == nil + assert result.pleroma[:settings_store] == nil result = AccountView.render("account.json", %{user: user, for: user}) - assert result.pleroma[:settings] == nil + assert result.pleroma[:settings_store] == nil end end From 7861974ab2cda55a97992f76e48ed082b234a7cf Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 31 May 2019 14:50:18 +0200 Subject: [PATCH 05/33] MastodonAPI: Add extension to set and get pleroma_settings_store. --- lib/pleroma/user/info.ex | 3 +- .../mastodon_api/mastodon_api_controller.ex | 12 +++- .../mastodon_api_controller_test.exs | 60 +++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index e6623160d..37cdf2fa7 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -210,7 +210,8 @@ def profile_update(info, params) do :hide_followers, :hide_favorites, :background, - :show_role + :show_role, + :pleroma_settings_store ]) end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 2110027c3..ce3e149cc 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -124,6 +124,9 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do end) end) |> add_if_present(params, "default_scope", :default_scope) + |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value -> + {:ok, Map.merge(user.info.pleroma_settings_store, value)} + end) |> add_if_present(params, "header", :banner, fn value -> with %Plug.Upload{} <- value, {:ok, object} <- ActivityPub.upload(value, type: :banner) do @@ -143,7 +146,10 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do CommonAPI.update(user) end - json(conn, AccountView.render("account.json", %{user: user, for: user})) + json( + conn, + AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true}) + ) else _e -> conn @@ -153,7 +159,9 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do end def verify_credentials(%{assigns: %{user: user}} = conn, _) do - account = AccountView.render("account.json", %{user: user, for: user}) + account = + AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true}) + json(conn, account) end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 93ef630f2..59a7967bd 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2322,6 +2322,66 @@ test "hides favorites for new users by default", %{conn: conn, current_user: cur end describe "updating credentials" do + test "sets user settings in a generic way", %{conn: conn} do + user = insert(:user) + + res_conn = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{ + "pleroma_settings_store" => %{ + pleroma_fe: %{ + theme: "bla" + } + } + }) + + assert user = json_response(res_conn, 200) + assert user["pleroma"]["settings_store"] == %{"pleroma_fe" => %{"theme" => "bla"}} + + user = Repo.get(User, user["id"]) + + res_conn = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{ + "pleroma_settings_store" => %{ + masto_fe: %{ + theme: "bla" + } + } + }) + + assert user = json_response(res_conn, 200) + + assert user["pleroma"]["settings_store"] == + %{ + "pleroma_fe" => %{"theme" => "bla"}, + "masto_fe" => %{"theme" => "bla"} + } + + user = Repo.get(User, user["id"]) + + res_conn = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{ + "pleroma_settings_store" => %{ + masto_fe: %{ + theme: "blub" + } + } + }) + + assert user = json_response(res_conn, 200) + + assert user["pleroma"]["settings_store"] == + %{ + "pleroma_fe" => %{"theme" => "bla"}, + "masto_fe" => %{"theme" => "blub"} + } + end + test "updates the user's bio", %{conn: conn} do user = insert(:user) user2 = insert(:user) From 10fe02acefca47e6013c4b0f70e4077a6d59d488 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 31 May 2019 14:58:28 +0200 Subject: [PATCH 06/33] Documentation: Document Settings store mechanism. --- docs/api/differences_in_mastoapi_responses.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 36b47608e..21c1b76e5 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -43,6 +43,7 @@ Has these additional fields under the `pleroma` object: - `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated - `hide_followers`: boolean, true when the user has follower hiding enabled - `hide_follows`: boolean, true when the user has follow hiding enabled +- `settings_store`: A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials` ### Source @@ -80,6 +81,14 @@ Additional parameters can be added to the JSON body/Form data: - `hide_favorites` - if true, user's favorites timeline will be hidden - `show_role` - if true, user's role (e.g admin, moderator) will be exposed to anyone in the API - `default_scope` - the scope returned under `privacy` key in Source subentity +- `pleroma_settings_store` - Opaque user settings to be saved on the backend. + +### Pleroma Settings Store +Pleroma has mechanism that allows frontends to save blobs of json for each user on the backend. This can be used to save frontend-specific settings for a user that the backend does not need to know about. + +The parameter should have a form of `{frontend_name: {...}}`, with `frontend_name` identifying your type of client, e.g. `pleroma_fe`. It will overwrite everything under this property, but will not overwrite other frontend's settings. + +This information is returned in the `verify_credentials` endpoint. ## Authentication From 7591a8928d7ca440dbc2d45428988208ef617bdc Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 31 May 2019 19:15:44 +0200 Subject: [PATCH 07/33] Setting Store: Document in changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4abb6eb8..f8ed529ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] ### Added +- Add a generic settings store for frontends / clients to use. - Optional SSH access mode. (Needs `erlang-ssh` package on some distributions). - [MongooseIM](https://github.com/esl/MongooseIM) http authentication support. - LDAP authentication From edf772d41ea7b44d7286e442061e94a347167be2 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 2 Jun 2019 09:44:42 +0000 Subject: [PATCH 08/33] mrf: allow a policy chain to be specified when filtering --- lib/pleroma/web/activity_pub/mrf.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 3bf7955f3..10ceef715 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -5,8 +5,8 @@ defmodule Pleroma.Web.ActivityPub.MRF do @callback filter(Map.t()) :: {:ok | :reject, Map.t()} - def filter(object) do - get_policies() + def filter(policies, %{} = object) do + policies |> Enum.reduce({:ok, object}, fn policy, {:ok, object} -> policy.filter(object) @@ -16,6 +16,8 @@ def filter(object) do end) end + def filter(%{} = object), do: get_policies() |> filter(object) + def get_policies do Pleroma.Config.get([:instance, :rewrite_policy], []) |> get_policies() end From 4087ccdab8fc906fb7029e8f98651555e40fea4f Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 2 Jun 2019 09:50:16 +0000 Subject: [PATCH 09/33] mrf: add subchain policy --- config/config.exs | 3 ++ .../web/activity_pub/mrf/subchain_policy.ex | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 lib/pleroma/web/activity_pub/mrf/subchain_policy.ex diff --git a/config/config.exs b/config/config.exs index 68168b279..450da8930 100644 --- a/config/config.exs +++ b/config/config.exs @@ -320,6 +320,9 @@ federated_timeline_removal: [], replace: [] +config :pleroma, :mrf_subchain, + match_actor: %{} + config :pleroma, :rich_media, enabled: true config :pleroma, :media_proxy, diff --git a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex new file mode 100644 index 000000000..7fb4a607e --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicy do + alias Pleroma.Config + alias Pleroma.Web.ActivityPub.MRF + + require Logger + + @behaviour MRF + + defp lookup_subchain(actor) do + with matches <- Config.get([:mrf_subchain, :match_actor]), + {match, subchain} <- Enum.find(matches, fn {k, _v} -> String.match?(actor, k) end) do + {:ok, match, subchain} + else + _e -> {:error, :notfound} + end + end + + @impl true + def filter(%{"actor" => actor} = message) do + with {:ok, match, subchain} <- lookup_subchain(actor) do + Logger.debug("[SubchainPolicy] Matched #{actor} against #{inspect(match)} with subchain #{inspect(subchain)}") + + subchain + |> MRF.filter(message) + else + _e -> {:ok, message} + end + end + + @impl true + def filter(message), do: {:ok, message} +end From 38a275b31f33262658e5bfc8310f44ed00cae9db Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 2 Jun 2019 10:08:51 +0000 Subject: [PATCH 10/33] test: add tests for subchain policy --- .../activity_pub/mrf/subchain_policy_test.exs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/web/activity_pub/mrf/subchain_policy_test.exs diff --git a/test/web/activity_pub/mrf/subchain_policy_test.exs b/test/web/activity_pub/mrf/subchain_policy_test.exs new file mode 100644 index 000000000..f7cbcad48 --- /dev/null +++ b/test/web/activity_pub/mrf/subchain_policy_test.exs @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do + use Pleroma.DataCase + + alias Pleroma.Web.ActivityPub.MRF.DropPolicy + alias Pleroma.Web.ActivityPub.MRF.SubchainPolicy + + @message %{ + "actor" => "https://banned.com", + "type" => "Create", + "object" => %{"content" => "hi"} + } + + test "it matches and processes subchains when the actor matches a configured target" do + Pleroma.Config.put([:mrf_subchain, :match_actor], %{ + ~r/^https:\/\/banned.com/s => [DropPolicy] + }) + + {:reject, _} = SubchainPolicy.filter(@message) + end + + test "it doesn't match and process subchains when the actor doesn't match a configured target" do + Pleroma.Config.put([:mrf_subchain, :match_actor], %{ + ~r/^https:\/\/borked.com/s => [DropPolicy] + }) + + {:ok, _message} = SubchainPolicy.filter(@message) + end +end From c724d8df9831409df7990dfea3fd07ffb627a156 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 2 Jun 2019 10:14:56 +0000 Subject: [PATCH 11/33] docs: document mrf_subchain --- docs/config.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/config.md b/docs/config.md index 67b062fe9..5d9de647c 100644 --- a/docs/config.md +++ b/docs/config.md @@ -81,6 +81,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default) * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See ``:mrf_simple`` section) + * `Pleroma.Web.ActivityPub.MRF.SubchainPolicy`: Selectively runs other MRF policies when messages match (see ``:mrf_subchain`` section) * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See ``:mrf_rejectnonpublic`` section) * `Pleroma.Web.ActivityPub.MRF.EnsureRePrepended`: Rewrites posts to ensure that replies to posts with subjects do not have an identical subject and instead begin with re:. * `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. @@ -224,6 +225,21 @@ relates to mascots on the mastodon frontend * `avatar_removal`: List of instances to strip avatars from * `banner_removal`: List of instances to strip banners from +## :mrf_subchain +This policy processes messages through an alternate pipeline when a given message matches certain criteria. +All criteria are configured as a map of regular expressions to lists of policy modules. + +* `match_actor`: Matches a series of regular expressions against the actor field. + +Example: + +``` +config :pleroma, :mrf_subchain, + match_actor: %{ + ~r/https:\/\/example.com/s => [Pleroma.Web.ActivityPub.MRF.DropPolicy] + } +``` + ## :mrf_rejectnonpublic * `allow_followersonly`: whether to allow followers-only posts * `allow_direct`: whether to allow direct messages From 561a21986d312f52bd1d06a477f1c88fd1adc727 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 2 Jun 2019 10:29:15 +0000 Subject: [PATCH 12/33] formatting --- config/config.exs | 3 +-- lib/pleroma/web/activity_pub/mrf/subchain_policy.ex | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config/config.exs b/config/config.exs index 450da8930..a5bb05a80 100644 --- a/config/config.exs +++ b/config/config.exs @@ -320,8 +320,7 @@ federated_timeline_removal: [], replace: [] -config :pleroma, :mrf_subchain, - match_actor: %{} +config :pleroma, :mrf_subchain, match_actor: %{} config :pleroma, :rich_media, enabled: true diff --git a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex index 7fb4a607e..765704389 100644 --- a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex @@ -22,7 +22,11 @@ defp lookup_subchain(actor) do @impl true def filter(%{"actor" => actor} = message) do with {:ok, match, subchain} <- lookup_subchain(actor) do - Logger.debug("[SubchainPolicy] Matched #{actor} against #{inspect(match)} with subchain #{inspect(subchain)}") + Logger.debug( + "[SubchainPolicy] Matched #{actor} against #{inspect(match)} with subchain #{ + inspect(subchain) + }" + ) subchain |> MRF.filter(message) From 83663caa81f1ccca37fe3898feb4ec2d829ad893 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sun, 2 Jun 2019 17:45:32 +0300 Subject: [PATCH 13/33] Ueberauth: extended format of OAUTH_CONSUMER_STRATEGIES to allow explicit dependency specification. --- config/config.exs | 6 +++++- docs/config.md | 2 +- mix.exs | 25 ++++++++++++++++++------- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/config/config.exs b/config/config.exs index 68168b279..5f1a1d0f8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -453,7 +453,11 @@ config :esshd, enabled: false -oauth_consumer_strategies = String.split(System.get_env("OAUTH_CONSUMER_STRATEGIES") || "") +oauth_consumer_strategies = + System.get_env("OAUTH_CONSUMER_STRATEGIES") + |> to_string() + |> String.split() + |> Enum.map(&hd(String.split(&1, ":"))) ueberauth_providers = for strategy <- oauth_consumer_strategies do diff --git a/docs/config.md b/docs/config.md index 67b062fe9..08088f269 100644 --- a/docs/config.md +++ b/docs/config.md @@ -492,7 +492,7 @@ Authentication / authorization settings. * `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`. * `oauth_consumer_template`: OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`. -* `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. +* `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-delimited string should be of format `` or `:` (e.g. `twitter` or `keycloak:ueberauth_keycloak_strategy` in case dependency is named differently than `ueberauth_`). ## OAuth consumer mode diff --git a/mix.exs b/mix.exs index b2017ef9b..df1a7ced4 100644 --- a/mix.exs +++ b/mix.exs @@ -51,16 +51,27 @@ def application do defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] + # Specifies OAuth dependencies. + defp oauth_deps do + oauth_strategy_packages = + System.get_env("OAUTH_CONSUMER_STRATEGIES") + |> to_string() + |> String.split() + |> Enum.map(fn strategy_entry -> + with [_strategy, dependency] <- String.split(strategy_entry, ":") do + dependency + else + [strategy] -> "ueberauth_#{strategy}" + end + end) + + for s <- oauth_strategy_packages, do: {String.to_atom(s), ">= 0.0.0"} + end + # Specifies your project dependencies. # # Type `mix help deps` for examples and options. defp deps do - oauth_strategies = String.split(System.get_env("OAUTH_CONSUMER_STRATEGIES") || "") - - oauth_deps = - for s <- oauth_strategies, - do: {String.to_atom("ueberauth_#{s}"), ">= 0.0.0"} - [ {:phoenix, "~> 1.4.1"}, {:plug_cowboy, "~> 2.0"}, @@ -121,7 +132,7 @@ defp deps do {:ex_rated, "~> 1.2"}, {:plug_static_index_html, "~> 1.0.0"}, {:excoveralls, "~> 0.11.1", only: :test} - ] ++ oauth_deps + ] ++ oauth_deps() end # Aliases are shortcuts or tasks specific to the current project. From 080e1aa70e4af4e9cdc0589f28648468bf116d6b Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 16:04:39 +0300 Subject: [PATCH 14/33] add option skip_thread_containment --- config/config.exs | 3 +- docs/config.md | 1 + lib/pleroma/user/info.ex | 5 +- lib/pleroma/web/activity_pub/activity_pub.ex | 7 +- lib/pleroma/web/streamer.ex | 25 +++++-- test/web/activity_pub/visibilty_test.exs | 43 +++++++++++ test/web/streamer_test.exs | 78 ++++++++++++++++++++ 7 files changed, 150 insertions(+), 12 deletions(-) diff --git a/config/config.exs b/config/config.exs index 68168b279..ada4fb48d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -237,7 +237,8 @@ max_report_comment_size: 1000, safe_dm_mentions: false, healthcheck: false, - remote_post_retention_days: 90 + remote_post_retention_days: 90, + skip_thread_containment: false config :pleroma, :app_account_creation, enabled: true, max_requests: 25, interval: 1800 diff --git a/docs/config.md b/docs/config.md index 67b062fe9..fbb9079e6 100644 --- a/docs/config.md +++ b/docs/config.md @@ -105,6 +105,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). (Default: `false`) * `healthcheck`: if set to true, system data will be shown on ``/api/pleroma/healthcheck``. * `remote_post_retention_days`: the default amount of days to retain remote posts when pruning the database +* `skip_thread_containment`: Skip filter out broken threads. the default is `false`. ## :app_account_creation REST API for creating an account settings diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index ef506c8da..d1fb4fe75 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -49,6 +49,8 @@ defmodule Pleroma.User.Info do default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} ) + field(:skip_thread_containment, :boolean, default: false) + # Found in the wild # ap_id -> Where is this used? # bio -> Where is this used? @@ -208,7 +210,8 @@ def profile_update(info, params) do :hide_followers, :hide_favorites, :background, - :show_role + :show_role, + :skip_thread_containment ]) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8add62406..f121ef01b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Conversation alias Pleroma.Notification alias Pleroma.Object @@ -73,7 +74,7 @@ defp check_actor_is_active(actor) do end defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(content) do - limit = Pleroma.Config.get([:instance, :remote_limit]) + limit = Config.get([:instance, :remote_limit]) String.length(content) <= limit end @@ -399,8 +400,8 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru end def block(blocker, blocked, activity_id \\ nil, local \\ true) do - outgoing_blocks = Pleroma.Config.get([:activitypub, :outgoing_blocks]) - unfollow_blocked = Pleroma.Config.get([:activitypub, :unfollow_blocked]) + outgoing_blocks = Config.get([:activitypub, :outgoing_blocks]) + unfollow_blocked = Config.get([:activitypub, :unfollow_blocked]) if unfollow_blocked do follow_activity = fetch_latest_follow(blocker, blocked) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 133decfc4..a23f80f26 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.Streamer do use GenServer require Logger alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Conversation.Participation alias Pleroma.Notification alias Pleroma.Object @@ -224,11 +225,10 @@ def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = ite mutes = user.info.mutes || [] reblog_mutes = user.info.muted_reblogs || [] - parent = Object.normalize(item) - - unless is_nil(parent) or item.actor in blocks or item.actor in mutes or - item.actor in reblog_mutes or not ActivityPub.contain_activity(item, user) or - parent.data["actor"] in blocks or parent.data["actor"] in mutes do + with parent when not is_nil(parent) <- Object.normalize(item), + true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), + true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), + true <- thread_containment(item, user) do send(socket.transport_pid, {:text, represent_update(item, user)}) end else @@ -264,8 +264,8 @@ def push_to_socket(topics, topic, item) do blocks = user.info.blocks || [] mutes = user.info.mutes || [] - unless item.actor in blocks or item.actor in mutes or - not ActivityPub.contain_activity(item, user) do + with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), + true <- thread_containment(item, user) do send(socket.transport_pid, {:text, represent_update(item, user)}) end else @@ -279,4 +279,15 @@ defp internal_topic(topic, socket) when topic in ~w[user direct] do end defp internal_topic(topic, _), do: topic + + @spec thread_containment(Activity.t(), User.t()) :: boolean() + defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true + + defp thread_containment(activity, user) do + if Config.get([:instance, :skip_thread_containment]) do + true + else + ActivityPub.contain_activity(activity, user) + end + end end diff --git a/test/web/activity_pub/visibilty_test.exs b/test/web/activity_pub/visibilty_test.exs index 466d980dc..e24df3cab 100644 --- a/test/web/activity_pub/visibilty_test.exs +++ b/test/web/activity_pub/visibilty_test.exs @@ -1,6 +1,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do use Pleroma.DataCase + alias Pleroma.Activity alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -121,4 +122,46 @@ test "get_visibility", %{ test "get_visibility with directMessage flag" do assert Visibility.get_visibility(%{data: %{"directMessage" => true}}) == "direct" end + + describe "entire_thread_visible_for_user?/2" do + test "returns false if not found activity", %{user: user} do + refute Visibility.entire_thread_visible_for_user?(%Activity{}, user) + end + + test "returns true if activity hasn't 'Create' type", %{user: user} do + activity = insert(:like_activity) + assert Visibility.entire_thread_visible_for_user?(activity, user) + end + + test "returns false when invalid recipients", %{user: user} do + author = insert(:user) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["test-user"]} + ) + ) + + refute Visibility.entire_thread_visible_for_user?(activity, user) + end + + test "returns true if user following to author" do + author = insert(:user) + user = insert(:user, following: [author.ap_id]) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => [user.ap_id]} + ) + ) + + assert Visibility.entire_thread_visible_for_user?(activity, user) + end + end end diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs index bfe18cb7f..c18b9f9fe 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -11,6 +11,16 @@ defmodule Pleroma.Web.StreamerTest do alias Pleroma.Web.Streamer import Pleroma.Factory + setup do + skip_thread_containment = Pleroma.Config.get([:instance, :skip_thread_containment]) + + on_exit(fn -> + Pleroma.Config.put([:instance, :skip_thread_containment], skip_thread_containment) + end) + + :ok + end + test "it sends to public" do user = insert(:user) other_user = insert(:user) @@ -68,6 +78,74 @@ test "it sends to public" do Task.await(task) end + describe "thread_containment" do + test "it doesn't send to user if recipients invalid and thread containment is enabled" do + Pleroma.Config.put([:instance, :skip_thread_containment], false) + author = insert(:user) + user = insert(:user, following: [author.ap_id]) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["TEST-FFF"]} + ) + ) + + task = Task.async(fn -> refute_receive {:text, _}, 1_000 end) + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + topics = %{"public" => [fake_socket]} + Streamer.push_to_socket(topics, "public", activity) + + Task.await(task) + end + + test "it sends message if recipients invalid and thread containment is disabled" do + Pleroma.Config.put([:instance, :skip_thread_containment], true) + author = insert(:user) + user = insert(:user, following: [author.ap_id]) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["TEST-FFF"]} + ) + ) + + task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + topics = %{"public" => [fake_socket]} + Streamer.push_to_socket(topics, "public", activity) + + Task.await(task) + end + + test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do + Pleroma.Config.put([:instance, :skip_thread_containment], false) + author = insert(:user) + user = insert(:user, following: [author.ap_id], info: %{skip_thread_containment: true}) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["TEST-FFF"]} + ) + ) + + task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + topics = %{"public" => [fake_socket]} + Streamer.push_to_socket(topics, "public", activity) + + Task.await(task) + end + end + test "it doesn't send to blocked users" do user = insert(:user) blocked_user = insert(:user) From 243d8ed94e031464a48621a55058882ba50de019 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Mon, 3 Jun 2019 18:00:32 +0300 Subject: [PATCH 15/33] Use workaround for the heavy checkmark symbol in iOS --- lib/pleroma/web/templates/layout/app.html.eex | 4 ++-- lib/pleroma/web/templates/o_auth/o_auth/show.html.eex | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index 818b3404b..98f7293bc 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -89,7 +89,7 @@ .scope:before { color: #b9b9ba; - content: "✔"; + content: "✔\fe0e"; margin-left: 1em; margin-right: 1em; } @@ -197,7 +197,7 @@ .scope:first-child:before { margin-left: 1em; - content: "✔"; + content: "✔\fe0e"; } .scope:after { diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 8b69c3033..ed4fb5ce7 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -56,4 +56,9 @@ <%= hidden_input f, :response_type, value: @response_type %> <%= hidden_input f, :redirect_uri, value: @redirect_uri %> <%= hidden_input f, :state, value: @state %> + +<%= if Pleroma.Config.oauth_consumer_enabled?() do %> + <%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %> +<% end %> + <% end %> From f2c4c99e0374a3657400d2e41fe8069f72a75337 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Mon, 3 Jun 2019 18:58:04 +0300 Subject: [PATCH 16/33] Remove repeated scope lists --- lib/pleroma/web/templates/layout/app.html.eex | 1 - .../templates/o_auth/o_auth/_scopes.html.eex | 16 ++++++++---- .../templates/o_auth/o_auth/consumer.html.eex | 4 ++- .../web/templates/o_auth/o_auth/show.html.eex | 25 ++----------------- 4 files changed, 16 insertions(+), 30 deletions(-) diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index 98f7293bc..b3cf9ed11 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -161,7 +161,6 @@ width: 100%; background-color: #931014; border: 1px solid #a06060; - color: #902020; border-radius: 4px; padding: 10px; margin-top: 20px; diff --git a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex index e6cfe108b..c9ec1ecbf 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex @@ -1,13 +1,19 @@
- <%= label @form, :scope, "Permissions" %> - + <%= label @form, :scope, "The following permissions will be granted" %>
<%= for scope <- @available_scopes do %> <%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %> -
+ <%= if scope in @scopes do %> +
+ <%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> + <%= label @form, :"scope_#{scope}", String.capitalize(scope) %> + <%= if scope in @scopes && scope do %> + <%= String.capitalize(scope) %> + <% end %> +
+ <% else %> <%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> - <%= label @form, :"scope_#{scope}", String.capitalize(scope) %> -
+ <% end %> <% end %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index 4bcda7300..4a0718851 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -1,7 +1,9 @@

Sign in with external provider

<%= form_for @conn, o_auth_path(@conn, :prepare_request), [as: "authorization", method: "get"], fn f -> %> - <%= render @view_module, "_scopes.html", Map.put(assigns, :form, f) %> +
+ <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %> +
<%= hidden_input f, :client_id, value: @client_id %> <%= hidden_input f, :redirect_uri, value: @redirect_uri %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index ed4fb5ce7..b17142ff8 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -18,7 +18,6 @@ <%= hidden_input f, :name, value: @params["name"] %> <%= hidden_input f, :password, value: @params["password"] %>
- <% else %>
<%= label f, :name, "Username" %> @@ -29,36 +28,16 @@ <%= password_input f, :password %>
<%= submit "Log In" %> -
- <%= label f, :scope, "The following permissions will be granted" %> -
- <%= for scope <- @available_scopes do %> - <%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %> - <%= if scope in @scopes do %> -
- <%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> - <%= label f, :"scope_#{scope}", String.capitalize(scope) %> - <%= if scope in @scopes && scope do %> - <%= String.capitalize(scope) %> - <% end %> -
- <% else %> - <%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> - <% end %> - <% end %> -
-
+ <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %> <% end %> -<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %> - <%= hidden_input f, :client_id, value: @client_id %> <%= hidden_input f, :response_type, value: @response_type %> <%= hidden_input f, :redirect_uri, value: @redirect_uri %> <%= hidden_input f, :state, value: @state %> +<% end %> <%= if Pleroma.Config.oauth_consumer_enabled?() do %> <%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %> <% end %> -<% end %> From be56801ddab84d9e21af75c7752e5898fe0dbecb Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 3 Jun 2019 19:26:43 +0300 Subject: [PATCH 17/33] Add index on inReplyTo for objects Fixes the performance of `get_existing_votes` --- .../20190603162018_add_object_in_reply_to_index.exs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 priv/repo/migrations/20190603162018_add_object_in_reply_to_index.exs diff --git a/priv/repo/migrations/20190603162018_add_object_in_reply_to_index.exs b/priv/repo/migrations/20190603162018_add_object_in_reply_to_index.exs new file mode 100644 index 000000000..df4ac7782 --- /dev/null +++ b/priv/repo/migrations/20190603162018_add_object_in_reply_to_index.exs @@ -0,0 +1,7 @@ +defmodule Pleroma.Repo.Migrations.AddObjectInReplyToIndex do + use Ecto.Migration + + def change do + create index(:objects, ["(data->>'inReplyTo')"], name: :objects_in_reply_to_index) + end +end From f13d6c7f78cfae4005b351248ce3e9069abf93e2 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 21:02:02 +0300 Subject: [PATCH 18/33] update api to set skip_thread_containment --- docs/api/differences_in_mastoapi_responses.md | 1 + .../mastodon_api/mastodon_api_controller.ex | 10 +++++++- .../web/mastodon_api/views/account_view.ex | 3 ++- .../web/twitter_api/twitter_api_controller.ex | 10 +++++++- .../web/twitter_api/views/user_view.ex | 3 ++- .../mastodon_api_controller_test.exs | 13 ++++++++++ .../twitter_api_controller_test.exs | 25 ++++++++++++++++++- 7 files changed, 60 insertions(+), 5 deletions(-) diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 36b47608e..ed156836d 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -80,6 +80,7 @@ Additional parameters can be added to the JSON body/Form data: - `hide_favorites` - if true, user's favorites timeline will be hidden - `show_role` - if true, user's role (e.g admin, moderator) will be exposed to anyone in the API - `default_scope` - the scope returned under `privacy` key in Source subentity +- `skip_thread_containment` - if true, skip filtering out broken threads ## Authentication diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 0d81fb840..52eed51c1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -117,7 +117,15 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do |> Enum.dedup() info_params = - [:no_rich_text, :locked, :hide_followers, :hide_follows, :hide_favorites, :show_role] + [ + :no_rich_text, + :locked, + :hide_followers, + :hide_follows, + :hide_favorites, + :show_role, + :skip_thread_containment + ] |> Enum.reduce(%{}, fn key, acc -> add_if_present(acc, params, to_string(key), key, fn value -> {:ok, ControllerHelper.truthy_param?(value)} diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b82d3319b..7b7e58eac 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -124,7 +124,8 @@ defp do_render("account.json", %{user: user} = opts) do hide_followers: user.info.hide_followers, hide_follows: user.info.hide_follows, hide_favorites: user.info.hide_favorites, - relationship: relationship + relationship: relationship, + skip_thread_containment: user.info.skip_thread_containment } } |> maybe_put_role(user, opts[:for]) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 1b6b33e69..6cf107d17 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -632,7 +632,15 @@ def raw_empty_array(conn, _params) do defp build_info_cng(user, params) do info_params = - ["no_rich_text", "locked", "hide_followers", "hide_follows", "hide_favorites", "show_role"] + [ + "no_rich_text", + "locked", + "hide_followers", + "hide_follows", + "hide_favorites", + "show_role", + "skip_thread_containment" + ] |> Enum.reduce(%{}, fn key, res -> if value = params[key] do Map.put(res, key, value == "true") diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index f0a4ddbd3..84875613a 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -118,7 +118,8 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do "pleroma" => %{ "confirmation_pending" => user_info.confirmation_pending, - "tags" => user.tags + "tags" => user.tags, + "skip_thread_containment" => user.info.skip_thread_containment } |> maybe_with_activation_status(user, for_user) } diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f5f87d8af..587df0481 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2378,6 +2378,19 @@ test "updates the user's hide_followers status", %{conn: conn} do assert user["pleroma"]["hide_followers"] == true end + test "updates the user's skip_thread_containment option", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{skip_thread_containment: "true"}) + |> json_response(200) + + assert response["pleroma"]["skip_thread_containment"] == true + assert refresh_record(user).info.skip_thread_containment + end + test "updates the user's hide_follows status", %{conn: conn} do user = insert(:user) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index bcd0f522d..8187ffd0e 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1495,7 +1495,7 @@ test "it sets and un-sets hide_follows", %{conn: conn} do "hide_follows" => "false" }) - user = Repo.get!(User, user.id) + user = refresh_record(user) assert user.info.hide_follows == false assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) end @@ -1548,6 +1548,29 @@ test "it sets and un-sets show_role", %{conn: conn} do assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) end + test "it sets and un-sets skip_thread_containment", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "true"}) + |> json_response(200) + + assert response["pleroma"]["skip_thread_containment"] == true + user = refresh_record(user) + assert user.info.skip_thread_containment + + response = + conn + |> assign(:user, user) + |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "false"}) + |> json_response(200) + + assert response["pleroma"]["skip_thread_containment"] == false + refute refresh_record(user).info.skip_thread_containment + end + test "it locks an account", %{conn: conn} do user = insert(:user) From 46c7e16512a4e51e2c062b9985bd04fb76487a28 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 21:05:45 +0300 Subject: [PATCH 19/33] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1fff876..419dcf3b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - OAuth: added job to clean expired access tokens - MRF: Support for rejecting reports from specific instances (`mrf_simple`) - MRF: Support for stripping avatars and banner images from specific instances (`mrf_simple`) +- Configuration: `skip_thread_containment` option ### Changed - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer From 64ada7f960eb45d5e06d431c0c27be1014106ff9 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 22:51:14 +0300 Subject: [PATCH 20/33] fix tests --- test/web/mastodon_api/account_view_test.exs | 9 ++++++--- test/web/twitter_api/views/user_view_test.exs | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index aaf2261bb..66ae8b4bb 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -67,7 +67,8 @@ test "Represent a user account" do hide_favorites: true, hide_followers: false, hide_follows: false, - relationship: %{} + relationship: %{}, + skip_thread_containment: false } } @@ -132,7 +133,8 @@ test "Represent a Service(bot) account" do hide_favorites: true, hide_followers: false, hide_follows: false, - relationship: %{} + relationship: %{}, + skip_thread_containment: false } } @@ -233,7 +235,8 @@ test "represent an embedded relationship" do domain_blocking: false, showing_reblogs: true, endorsed: false - } + }, + skip_thread_containment: false } } diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs index 74526673c..9870c17c0 100644 --- a/test/web/twitter_api/views/user_view_test.exs +++ b/test/web/twitter_api/views/user_view_test.exs @@ -99,7 +99,8 @@ test "A user" do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" @@ -152,7 +153,8 @@ test "A user for a given other follower", %{user: user} do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" @@ -197,7 +199,8 @@ test "A user that follows you", %{user: user} do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" @@ -279,7 +282,8 @@ test "A blocked user for the blocker" do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" From 7758148990184ac25e097dc7358a918b89aa3ca9 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 4 Jun 2019 05:37:31 +0000 Subject: [PATCH 21/33] update CHANGELOG for mrf_subchain --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1fff876..532e76fbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - OAuth: added job to clean expired access tokens - MRF: Support for rejecting reports from specific instances (`mrf_simple`) - MRF: Support for stripping avatars and banner images from specific instances (`mrf_simple`) +- MRF: Support for running subchains. ### Changed - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer From 84cc131b59ad6c8910735c982757fee598de8757 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Tue, 4 Jun 2019 05:46:19 +0000 Subject: [PATCH 22/33] Add missing HTTP Request mocks --- test/object/containment_test.exs | 5 +++++ test/support/http_request_mock.ex | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/test/object/containment_test.exs b/test/object/containment_test.exs index 452064093..a7a046203 100644 --- a/test/object/containment_test.exs +++ b/test/object/containment_test.exs @@ -6,6 +6,11 @@ defmodule Pleroma.Object.ContainmentTest do import Pleroma.Factory + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + describe "general origin containment" do test "contain_origin_from_id() catches obvious spoofing attempts" do data = %{ diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 36b9265e7..67ef0928a 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -243,6 +243,14 @@ def get("https://niu.moe/users/rye", _, _, Accept: "application/activity+json") }} end + def get("https://n1u.moe/users/rye", _, _, Accept: "application/activity+json") do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/httpoison_mock/rye.json") + }} + end + def get("http://mastodon.example.org/users/admin/statuses/100787282858396771", _, _, _) do {:ok, %Tesla.Env{ @@ -302,6 +310,10 @@ def get("http://mastodon.example.org/users/admin", _, _, Accept: "application/ac }} end + def get("http://mastodon.example.org/users/gargron", _, _, Accept: "application/activity+json") do + {:error, :nxdomain} + end + def get( "http://mastodon.example.org/@admin/99541947525187367", _, @@ -546,6 +558,15 @@ def get( }} end + def get( + "http://gs.example.org:4040/index.php/user/1", + _, + _, + Accept: "application/activity+json" + ) do + {:ok, %Tesla.Env{status: 406, body: ""}} + end + def get("http://gs.example.org/index.php/api/statuses/user_timeline/1.atom", _, _, _) do {:ok, %Tesla.Env{ From 1c6cf0a348661612070d32c6f4f5d980d9254ac0 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 4 Jun 2019 06:19:44 +0000 Subject: [PATCH 23/33] nodeinfo: add pollLimits to metadata --- lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 59f3d4e11..57f5b61bb 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -97,6 +97,7 @@ def raw_nodeinfo do "pleroma_api", "mastodon_api", "mastodon_api_streaming", + "polls", if Config.get([:media_proxy, :enabled]) do "media_proxy" end, @@ -149,6 +150,7 @@ def raw_nodeinfo do }, staffAccounts: staff_accounts, federation: federation_response, + pollLimits: Config.get([:instance, :poll_limits]), postFormats: Config.get([:instance, :allowed_post_formats]), uploadLimits: %{ general: Config.get([:instance, :upload_limit]), From 37a4ba06244705dae0a4b0eea9f6f4ac647f5dfb Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 4 Jun 2019 08:45:03 +0000 Subject: [PATCH 24/33] utils: access inReplyTo as an explicit string when fetching poll results` --- lib/pleroma/web/activity_pub/utils.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index b292d7d8d..b8159e9e5 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -797,7 +797,7 @@ def get_existing_votes(actor, %{data: %{"id" => id}}) do where: fragment("(?)->>'actor' = ?", activity.data, ^actor), where: fragment( - "(?)->'inReplyTo' = ?", + "(?)->>'inReplyTo' = ?", object.data, ^to_string(id) ), From 96121315f3e9aebc57d36a669fc4003905cd0ba6 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 4 Jun 2019 12:41:24 +0300 Subject: [PATCH 25/33] fix merge --- docs/api/differences_in_mastoapi_responses.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 88a43de38..623d4fbf5 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -90,7 +90,6 @@ Pleroma has mechanism that allows frontends to save blobs of json for each user The parameter should have a form of `{frontend_name: {...}}`, with `frontend_name` identifying your type of client, e.g. `pleroma_fe`. It will overwrite everything under this property, but will not overwrite other frontend's settings. This information is returned in the `verify_credentials` endpoint. ->>>>>>> develop ## Authentication From 29b022bb597f36621ef3f5056c5ca2b7f0c8edbe Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 4 Jun 2019 12:42:10 +0300 Subject: [PATCH 26/33] Restrict `get_existing_votes` to only get Create activities --- lib/pleroma/web/activity_pub/utils.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index b8159e9e5..faae7e747 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -794,6 +794,7 @@ def get_existing_votes(actor, %{data: %{"id" => id}}) do query = from( [activity, object: object] in Activity.with_preloaded_object(Activity), + where: fragment("(?)->>'type' = 'Create'", activity.data), where: fragment("(?)->>'actor' = ?", activity.data, ^actor), where: fragment( From e74581a5c4c3aca68a304efb683dffed80d1337f Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 4 Jun 2019 12:01:21 +0200 Subject: [PATCH 27/33] Emoji: Don't die when files are present in the emoji folder. --- lib/pleroma/emoji.ex | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 7d12eff7f..de7fcc1ce 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -97,10 +97,22 @@ defp load do # There was some other error Logger.error("Could not access the custom emoji directory #{emoji_dir_path}: #{e}") - {:ok, packs} -> + {:ok, results} -> + grouped = Enum.group_by(results, &File.dir?/1) + packs = grouped[true] || [] + files = grouped[false] || [] + # Print the packs we've found Logger.info("Found emoji packs: #{Enum.join(packs, ", ")}") + if not Enum.empty?(files) do + Logger.warn( + "Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{ + Enum.join(files, ", ") + }" + ) + end + emojis = Enum.flat_map( packs, From 17383861edf6c9d7308101182607e7ff9202af73 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 4 Jun 2019 13:38:24 +0300 Subject: [PATCH 28/33] Fix CommonAPI.vote returning tuples inside of the activity array instead of just activities --- lib/pleroma/web/common_api/common_api.ex | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 5212d5ce5..ad3c03c55 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -132,13 +132,16 @@ def vote(user, object, choices) do Enum.map(choices, fn index -> answer_data = make_answer_data(user, object, Enum.at(options, index)["name"]) - ActivityPub.create(%{ - to: answer_data["to"], - actor: user, - context: object.data["context"], - object: answer_data, - additional: %{"cc" => answer_data["cc"]} - }) + {:ok, activity} = + ActivityPub.create(%{ + to: answer_data["to"], + actor: user, + context: object.data["context"], + object: answer_data, + additional: %{"cc" => answer_data["cc"]} + }) + + activity end) object = Object.get_cached_by_ap_id(object.data["id"]) From bbff7554de7f8c3965387fb3509728c1f2c2d04b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 4 Jun 2019 13:47:53 +0300 Subject: [PATCH 29/33] Add tests for get_existing_votes --- test/web/activity_pub/utils_test.exs | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index c57fae437..de741c64b 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -1,6 +1,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do use Pleroma.DataCase alias Pleroma.Activity + alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils @@ -204,4 +205,46 @@ test "make_json_ld_header/0" do ] } end + + describe "get_existing_votes" do + test "fetches existing votes" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "How do I pronounce LaTeX?", + "poll" => %{ + "options" => ["laytekh", "lahtekh", "latex"], + "expires_in" => 20, + "multiple" => true + } + }) + + object = Object.normalize(activity) + {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1]) + assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes) + end + + test "fetches only Create activities" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "Are we living in a society?", + "poll" => %{ + "options" => ["yes", "no"], + "expires_in" => 20 + } + }) + + object = Object.normalize(activity) + {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0]) + vote_object = Object.normalize(vote) + {:ok, _activity, _object} = ActivityPub.like(user, vote_object) + [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object) + assert fetched_vote.id == vote.id + end + end end From a3a7178b604d8bc589a8e3ac06abac094cce5e17 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 4 Jun 2019 13:58:36 +0200 Subject: [PATCH 30/33] Participations: Filter out participations without activities. --- lib/pleroma/conversation/participation.ex | 1 + test/conversation/participation_test.exs | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 2a11f9069..2c13c4b40 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -79,5 +79,6 @@ def for_user_with_last_activity_id(user, params \\ %{}) do | last_activity_id: activity_id } end) + |> Enum.filter(& &1.last_activity_id) end end diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 568953b07..0e60bfca5 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -86,4 +86,17 @@ test "gets all the participations for a user, ordered by updated at descending" assert participation_one.last_activity_id == activity_three.id end + + test "Doesn't die when the conversation gets empty" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) + [participation] = Participation.for_user_with_last_activity_id(user) + + assert participation.last_activity_id == activity.id + + {:ok, _} = CommonAPI.delete(activity.id, user) + + [] = Participation.for_user_with_last_activity_id(user) + end end From 0acfcf6c522a82ca416b6664d588d3daa32a6fba Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 4 Jun 2019 15:04:36 +0300 Subject: [PATCH 31/33] update ActivityPub#fetch_activities_query --- lib/pleroma/web/activity_pub/activity_pub.ex | 32 +++++++++----------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8c4d0c15d..eefed5832 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -558,14 +558,11 @@ defp restrict_visibility(query, %{visibility: visibility}) defp restrict_visibility(query, %{visibility: visibility}) when visibility in @valid_visibilities do - query = - from( - a in query, - where: - fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) - ) - - query + from( + a in query, + where: + fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) + ) end defp restrict_visibility(_query, %{visibility: visibility}) @@ -575,17 +572,17 @@ defp restrict_visibility(_query, %{visibility: visibility}) defp restrict_visibility(query, _visibility), do: query - defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}) do - query = - from( - a in query, - where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) - ) + defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _), + do: query - query + defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}, _) do + from( + a in query, + where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) + ) end - defp restrict_thread_visibility(query, _), do: query + defp restrict_thread_visibility(query, _, _), do: query def fetch_user_activities(user, reading_user, params \\ %{}) do params = @@ -863,6 +860,7 @@ defp maybe_order(query, _), do: query def fetch_activities_query(recipients, opts \\ %{}) do base_query = from(activity in Activity) + config = Enum.into(Config.get([:instance]), %{}) base_query |> maybe_preload_objects(opts) @@ -883,7 +881,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_muted(opts) |> restrict_media(opts) |> restrict_visibility(opts) - |> restrict_thread_visibility(opts) + |> restrict_thread_visibility(opts, config) |> restrict_replies(opts) |> restrict_reblogs(opts) |> restrict_pinned(opts) From 1e7bb69a957c279eb75ed72cca779caa9d8f25ce Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 4 Jun 2019 15:20:24 +0300 Subject: [PATCH 32/33] update ActivityPub#fetch_activities_query --- lib/pleroma/web/activity_pub/activity_pub.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index eefed5832..c0e3d1478 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -575,6 +575,13 @@ defp restrict_visibility(query, _visibility), do: query defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _), do: query + defp restrict_thread_visibility( + query, + %{"user" => %User{info: %{skip_thread_containment: true}}}, + _ + ), + do: query + defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}, _) do from( a in query, @@ -860,7 +867,10 @@ defp maybe_order(query, _), do: query def fetch_activities_query(recipients, opts \\ %{}) do base_query = from(activity in Activity) - config = Enum.into(Config.get([:instance]), %{}) + + config = %{ + skip_thread_containment: Config.get([:instance, :skip_thread_containment]) + } base_query |> maybe_preload_objects(opts) From b5e3b1e58ad9f4d8237821572e4d149eea881ff2 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 4 Jun 2019 16:44:56 +0200 Subject: [PATCH 33/33] Mix: Swallow git error messages during version number handling. Otherwise sometimes a 'fatal' message will be printed, confusing users. --- mix.exs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index df1a7ced4..9447a2e4f 100644 --- a/mix.exs +++ b/mix.exs @@ -157,7 +157,8 @@ defp aliases do # * the mix environment if different than prod defp version(version) do {git_tag, git_pre_release} = - with {tag, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=0"]), + with {tag, 0} <- + System.cmd("git", ["describe", "--tags", "--abbrev=0"], stderr_to_stdout: true), tag = String.trim(tag), {describe, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=8"]), describe = String.trim(describe),