From d6d5f46baea90e9b8a305a010457ac6d404d8829 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 11 Apr 2019 16:02:38 +0000 Subject: [PATCH 01/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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 243d8ed94e031464a48621a55058882ba50de019 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Mon, 3 Jun 2019 18:00:32 +0300 Subject: [PATCH 14/21] 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 15/21] 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 16/21] 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 cfc3c62b2ffde1a2fbc7764ad1cbc292e7f20f74 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 3 Jun 2019 20:42:08 +0300 Subject: [PATCH 17/21] Add missing tag index on objects The previous activity index is useless because objects are not embedded anymore and instead a joined object is queried. --- .../20190603173419_add_tag_index_to_objects.exs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs diff --git a/priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs b/priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs new file mode 100644 index 000000000..c915a0213 --- /dev/null +++ b/priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs @@ -0,0 +1,8 @@ +defmodule Pleroma.Repo.Migrations.AddTagIndexToObjects do + use Ecto.Migration + + def change do + drop_if_exists index(:activities, ["(data #> '{\"object\",\"tag\"}')"], using: :gin, name: :activities_tags) + create index(:objects, ["(data->'tag')"], using: :gin, name: :objects_tags) + end +end From 7758148990184ac25e097dc7358a918b89aa3ca9 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 4 Jun 2019 05:37:31 +0000 Subject: [PATCH 18/21] 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 19/21] 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 20/21] 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 21/21] 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) ),