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 8333bc9217..7d2d609d13 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 87278e636c..c7b4ef7922 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 c7b4ef7922..45f2b5cc07 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 6397e2737b..e6623160d0 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 b82d3319b4..04d4853409 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 aaf2261bbd..ca73d6581a 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 04d4853409..dc32a15254 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 ca73d6581a..5e6f1d00b7 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 e6623160d0..37cdf2fa76 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 2110027c3d..ce3e149ccc 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 93ef630f29..59a7967bd1 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 36b47608e1..21c1b76e58 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 b4abb6eb8e..f8ed529aea 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 3bf7955f32..10ceef715f 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 68168b2796..450da89304 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 0000000000..7fb4a607e8 --- /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 0000000000..f7cbcad48e --- /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 67b062fe93..5d9de647c2 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 450da89304..a5bb05a800 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 7fb4a607e8..7657043897 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 68168b2796..5f1a1d0f8a 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 67b062fe93..08088f2696 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 b2017ef9bf..df1a7ced44 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 818b3404bf..98f7293bca 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 8b69c30335..ed4fb5ce76 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 98f7293bca..b3cf9ed115 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 e6cfe108b9..c9ec1ecbfa 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 4bcda7300e..4a0718851a 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 ed4fb5ce76..b17142ff8f 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 0000000000..df4ac77822 --- /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 0000000000..c915a02130 --- /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 ff1fff8760..532e76fbeb 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 4520640939..a7a046203a 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 36b9265e7d..67ef0928a1 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 59f3d4e116..57f5b61bb3 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 b292d7d8d5..b8159e9e5d 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) ),