From a12b6454bb0a270732f9b55f8d4366c9add44136 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 16 Dec 2019 22:24:03 +0700 Subject: [PATCH 01/12] Add an option to require fetches to be signed --- CHANGELOG.md | 1 + config/config.exs | 3 +- docs/configuration/cheatsheet.md | 9 ++-- lib/pleroma/plugs/http_signature.ex | 43 ++++++++++++------ test/plugs/http_signature_plug_test.exs | 58 +++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c133cd9ec..ee9e1091c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - User notification settings: Add `privacy_option` option. - User settings: Add _This account is a_ option. - OAuth: admin scopes support (relevant setting: `[:auth, :enforce_oauth_admin_scope_usage]`). +- Add an option `authorized_fetch_mode` to requrie HTTP Signature for AP fetches.
API Changes diff --git a/config/config.exs b/config/config.exs index 370ddd855..541fcc2d4 100644 --- a/config/config.exs +++ b/config/config.exs @@ -343,7 +343,8 @@ unfollow_blocked: true, outgoing_blocks: true, follow_handshake_timeout: 500, - sign_object_fetches: true + sign_object_fetches: true, + authorized_fetch_mode: false config :pleroma, :streamer, workers: 3, diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index ce2a14210..8fa4a1747 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -147,10 +147,11 @@ config :pleroma, :mrf_user_allowlist, * `:reject` rejects the message entirely ### :activitypub -* ``unfollow_blocked``: Whether blocks result in people getting unfollowed -* ``outgoing_blocks``: Whether to federate blocks to other instances -* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question -* ``sign_object_fetches``: Sign object fetches with HTTP signatures +* `unfollow_blocked`: Whether blocks result in people getting unfollowed +* `outgoing_blocks`: Whether to federate blocks to other instances +* `deny_follow_blocked`: Whether to disallow following an account that has blocked the user in question +* `sign_object_fetches`: Sign object fetches with HTTP signatures +* `authorized_fetch_mode`: Require HTTP Signature for AP fetches ### :fetch_initial_posts * `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex index 23d22a712..ecd7a55bf 100644 --- a/lib/pleroma/plugs/http_signature.ex +++ b/lib/pleroma/plugs/http_signature.ex @@ -15,25 +15,23 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do end def call(conn, _opts) do - headers = get_req_header(conn, "signature") - signature = Enum.at(headers, 0) + conn + |> maybe_assign_valid_signature() + |> maybe_require_signature() + end - if signature do + defp maybe_assign_valid_signature(conn) do + if has_signature_header?(conn) do # set (request-target) header to the appropriate value # we also replace the digest header with the one we computed - conn = - conn - |> put_req_header( - "(request-target)", - String.downcase("#{conn.method}") <> " #{conn.request_path}" - ) + request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}" conn = - if conn.assigns[:digest] do - conn - |> put_req_header("digest", conn.assigns[:digest]) - else - conn + conn + |> put_req_header("(request-target)", request_target) + |> case do + %{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest) + conn -> conn end assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) @@ -42,4 +40,21 @@ def call(conn, _opts) do conn end end + + defp has_signature_header?(conn) do + conn |> get_req_header("signature") |> Enum.at(0, false) + end + + defp maybe_require_signature(%{assigns: %{valid_signature: true}} = conn), do: conn + + defp maybe_require_signature(conn) do + if Pleroma.Config.get([:activitypub, :authorized_fetch_mode], false) do + conn + |> put_status(:unauthorized) + |> Phoenix.Controller.text("Request not signed") + |> halt() + else + conn + end + end end diff --git a/test/plugs/http_signature_plug_test.exs b/test/plugs/http_signature_plug_test.exs index d8ace36da..007193dd9 100644 --- a/test/plugs/http_signature_plug_test.exs +++ b/test/plugs/http_signature_plug_test.exs @@ -23,7 +23,65 @@ test "it call HTTPSignatures to check validity if the actor sighed it" do |> HTTPSignaturePlug.call(%{}) assert conn.assigns.valid_signature == true + assert conn.halted == false assert called(HTTPSignatures.validate_conn(:_)) end end + + describe "requries a signature when `authorized_fetch_mode` is enabled" do + setup do + Pleroma.Config.put([:activitypub, :authorized_fetch_mode], true) + + on_exit(fn -> + Pleroma.Config.put([:activitypub, :authorized_fetch_mode], false) + end) + + params = %{"actor" => "http://mastodon.example.org/users/admin"} + conn = build_conn(:get, "/doesntmattter", params) + + [conn: conn] + end + + test "when signature header is present", %{conn: conn} do + with_mock HTTPSignatures, validate_conn: fn _ -> false end do + conn = + conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == false + assert conn.halted == true + assert conn.status == 401 + assert conn.state == :sent + assert conn.resp_body == "Request not signed" + assert called(HTTPSignatures.validate_conn(:_)) + end + + with_mock HTTPSignatures, validate_conn: fn _ -> true end do + conn = + conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == true + assert conn.halted == false + assert called(HTTPSignatures.validate_conn(:_)) + end + end + + test "halts the connection when `signature` header is not present", %{conn: conn} do + conn = HTTPSignaturePlug.call(conn, %{}) + assert conn.assigns[:valid_signature] == nil + assert conn.halted == true + assert conn.status == 401 + assert conn.state == :sent + assert conn.resp_body == "Request not signed" + end + end end From e1fa8c11a9ea26f54a231cbdacdc8befe634b57e Mon Sep 17 00:00:00 2001 From: minibikini Date: Mon, 16 Dec 2019 18:39:59 +0000 Subject: [PATCH 02/12] Apply suggestion to test/plugs/http_signature_plug_test.exs --- test/plugs/http_signature_plug_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/plugs/http_signature_plug_test.exs b/test/plugs/http_signature_plug_test.exs index 007193dd9..77e790288 100644 --- a/test/plugs/http_signature_plug_test.exs +++ b/test/plugs/http_signature_plug_test.exs @@ -28,7 +28,7 @@ test "it call HTTPSignatures to check validity if the actor sighed it" do end end - describe "requries a signature when `authorized_fetch_mode` is enabled" do + describe "requires a signature when `authorized_fetch_mode` is enabled" do setup do Pleroma.Config.put([:activitypub, :authorized_fetch_mode], true) From d81c3afbb2f020226909afed851d2aa623fdcdb0 Mon Sep 17 00:00:00 2001 From: minibikini Date: Mon, 16 Dec 2019 18:40:12 +0000 Subject: [PATCH 03/12] Apply suggestion to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee9e1091c..3c2b49962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - User notification settings: Add `privacy_option` option. - User settings: Add _This account is a_ option. - OAuth: admin scopes support (relevant setting: `[:auth, :enforce_oauth_admin_scope_usage]`). -- Add an option `authorized_fetch_mode` to requrie HTTP Signature for AP fetches. +- Add an option `authorized_fetch_mode` to require HTTP Signatures for AP fetches.
API Changes From 36d66d965519037d086ad5080ccf833801c3381e Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 17 Dec 2019 02:06:58 +0700 Subject: [PATCH 04/12] Fix typo --- CHANGELOG.md | 2 +- docs/configuration/cheatsheet.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c2b49962..93c7485aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - User notification settings: Add `privacy_option` option. - User settings: Add _This account is a_ option. - OAuth: admin scopes support (relevant setting: `[:auth, :enforce_oauth_admin_scope_usage]`). -- Add an option `authorized_fetch_mode` to require HTTP Signatures for AP fetches. +- Add an option `authorized_fetch_mode` to require HTTP signatures for AP fetches.
API Changes diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 8fa4a1747..cdc7c5ee0 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -151,7 +151,7 @@ config :pleroma, :mrf_user_allowlist, * `outgoing_blocks`: Whether to federate blocks to other instances * `deny_follow_blocked`: Whether to disallow following an account that has blocked the user in question * `sign_object_fetches`: Sign object fetches with HTTP signatures -* `authorized_fetch_mode`: Require HTTP Signature for AP fetches +* `authorized_fetch_mode`: Require HTTP signatures for AP fetches ### :fetch_initial_posts * `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts From 775212121cc3eb108bca6c4b94a3fdf6d8d8fcd1 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 19 Dec 2019 20:17:18 +0700 Subject: [PATCH 05/12] Verify HTTP signatures only when request accepts "activity+json" type --- lib/pleroma/plugs/http_signature.ex | 13 +++++++++---- test/plugs/http_signature_plug_test.exs | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex index ecd7a55bf..477a5b578 100644 --- a/lib/pleroma/plugs/http_signature.ex +++ b/lib/pleroma/plugs/http_signature.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do import Plug.Conn + import Phoenix.Controller, only: [get_format: 1, text: 2] require Logger def init(options) do @@ -15,9 +16,13 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do end def call(conn, _opts) do - conn - |> maybe_assign_valid_signature() - |> maybe_require_signature() + if get_format(conn) == "activity+json" do + conn + |> maybe_assign_valid_signature() + |> maybe_require_signature() + else + conn + end end defp maybe_assign_valid_signature(conn) do @@ -51,7 +56,7 @@ defp maybe_require_signature(conn) do if Pleroma.Config.get([:activitypub, :authorized_fetch_mode], false) do conn |> put_status(:unauthorized) - |> Phoenix.Controller.text("Request not signed") + |> text("Request not signed") |> halt() else conn diff --git a/test/plugs/http_signature_plug_test.exs b/test/plugs/http_signature_plug_test.exs index 77e790288..55e8bafc0 100644 --- a/test/plugs/http_signature_plug_test.exs +++ b/test/plugs/http_signature_plug_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do alias Pleroma.Web.Plugs.HTTPSignaturePlug import Plug.Conn + import Phoenix.Controller, only: [put_format: 2] import Mock test "it call HTTPSignatures to check validity if the actor sighed it" do @@ -20,6 +21,7 @@ test "it call HTTPSignatures to check validity if the actor sighed it" do "signature", "keyId=\"http://mastodon.example.org/users/admin#main-key" ) + |> put_format("activity+json") |> HTTPSignaturePlug.call(%{}) assert conn.assigns.valid_signature == true @@ -37,7 +39,7 @@ test "it call HTTPSignatures to check validity if the actor sighed it" do end) params = %{"actor" => "http://mastodon.example.org/users/admin"} - conn = build_conn(:get, "/doesntmattter", params) + conn = build_conn(:get, "/doesntmattter", params) |> put_format("activity+json") [conn: conn] end From e02eb8de3ec8130e9808c6a54a5c78f7ec8feb23 Mon Sep 17 00:00:00 2001 From: ilja Date: Wed, 15 Jan 2020 09:12:24 +0100 Subject: [PATCH 06/12] Add OTP to updating.md * I removed the Update section from the OTP install and added it to updating.md * I also added a link to the updating.md from the OTP install page * I added a Questions section to the OTP install, similar to the debian_based_en.md * Restructured the updating.md a bit I would very much also like to link to the changelog, but I don't know how to do it because I can't find the page in the docs? --- docs/administration/updating.md | 17 +++++++++++++++++ docs/installation/otp_en.md | 17 ++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/administration/updating.md b/docs/administration/updating.md index 84e6ef18d..2a08dac1f 100644 --- a/docs/administration/updating.md +++ b/docs/administration/updating.md @@ -1,4 +1,21 @@ # Updating your instance + +You should **always check the release notes/changelog** in case there are config deprecations, special update special update steps, etc. + +Besides that, doing the following is generally enough: + +## For OTP installations + +```sh +# Download the new release +su pleroma -s $SHELL -lc "./bin/pleroma_ctl update" + +# Migrate the database, you are advised to stop the instance before doing that +su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" +``` + +## For from source installations (using git) + 1. Go to the working directory of Pleroma (default is `/opt/pleroma`) 2. Run `git pull`. This pulls the latest changes from upstream. 3. Run `mix deps.get`. This pulls in any new dependencies. diff --git a/docs/installation/otp_en.md b/docs/installation/otp_en.md index 93230806c..aab5197a2 100644 --- a/docs/installation/otp_en.md +++ b/docs/installation/otp_en.md @@ -259,19 +259,14 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl user new joeuser joeuser@sld.tld --a ``` This will create an account withe the username of 'joeuser' with the email address of joeuser@sld.tld, and set that user's account as an admin. This will result in a link that you can paste into the browser, which logs you in and enables you to set the password. -### Updating -Generally, doing the following is enough: -```sh -# Download the new release -su pleroma -s $SHELL -lc "./bin/pleroma_ctl update" - -# Migrate the database, you are advised to stop the instance before doing that -su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" -``` -But you should **always check the release notes/changelog** in case there are config deprecations, special update steps, etc. - ## Further reading * [Backup your instance](../administration/backup.md) * [Hardening your instance](../configuration/hardening.md) * [How to activate mediaproxy](../configuration/howto_mediaproxy.md) +* [Updating your instance](../administration/updating.md) + +## Questions + +Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**. + From 7bfb8ed14d2d222e6fcd7afe54f229f68370f061 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 21 Jan 2020 16:16:59 +0100 Subject: [PATCH 07/12] remote_follow_controller.ex: Redirect to the user page on success Closes: https://git.pleroma.social/pleroma/pleroma/issues/1245 --- .../controllers/remote_follow_controller.ex | 6 +++--- .../remote_follow_controller_test.exs | 18 +++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index e0d4d5632..fbf31c7eb 100644 --- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors +# Copyright © 2017-2020 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do @@ -69,7 +69,7 @@ defp is_status?(acct) do def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, {:ok, _, _, _} <- CommonAPI.follow(user, followee) do - render(conn, "followed.html", %{error: false}) + redirect(conn, to: "/users/#{followee.id}") else error -> handle_follow_error(conn, error) @@ -80,7 +80,7 @@ def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, {_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee}, {:ok, _, _, _} <- CommonAPI.follow(user, followee) do - render(conn, "followed.html", %{error: false}) + redirect(conn, to: "/users/#{followee.id}") else error -> handle_follow_error(conn, error) diff --git a/test/web/twitter_api/remote_follow_controller_test.exs b/test/web/twitter_api/remote_follow_controller_test.exs index 444949375..80a42989d 100644 --- a/test/web/twitter_api/remote_follow_controller_test.exs +++ b/test/web/twitter_api/remote_follow_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors +# Copyright © 2017-2020 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do @@ -92,15 +92,13 @@ test "follows user", %{conn: conn} do user = insert(:user) user2 = insert(:user) - response = + conn = conn |> assign(:user, user) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - |> response(200) - assert response =~ "Account followed!" - assert user2.follower_address in User.following(user) + assert redirected_to(conn) == "/users/#{user2.id}" end test "returns error when user is deactivated", %{conn: conn} do @@ -149,14 +147,13 @@ test "returns success result when user already in followers", %{conn: conn} do user2 = insert(:user) {:ok, _, _, _} = CommonAPI.follow(user, user2) - response = + conn = conn |> assign(:user, refresh_record(user)) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - |> response(200) - assert response =~ "Account followed!" + assert redirected_to(conn) == "/users/#{user2.id}" end end @@ -165,14 +162,13 @@ test "follows", %{conn: conn} do user = insert(:user) user2 = insert(:user) - response = + conn = conn |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) - |> response(200) - assert response =~ "Account followed!" + assert redirected_to(conn) == "/users/#{user2.id}" assert user2.follower_address in User.following(user) end From 314928333ad245df6dbbcced904428b8f2beb3c2 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 19 Feb 2020 17:16:45 +0100 Subject: [PATCH 08/12] Pleroma API: Add endpoint to get reaction information on a single emoji --- .../controllers/pleroma_api_controller.ex | 25 +++++++++++------- lib/pleroma/web/router.ex | 1 + .../pleroma_api_controller_test.exs | 26 +++++++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 108e48438..f86a068fb 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -41,24 +41,29 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) - def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do + def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id} = params) do with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <- Object.normalize(activity) do reactions = emoji_reactions |> Enum.map(fn [emoji, user_ap_ids] -> - users = - Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1) - |> Enum.filter(& &1) + if params["emoji"] && params["emoji"] != emoji do + nil + else + users = + Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1) + |> Enum.filter(& &1) - %{ - name: emoji, - count: length(users), - accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}), - me: !!(user && user.ap_id in user_ap_ids) - } + %{ + name: emoji, + count: length(users), + accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}), + me: !!(user && user.ap_id in user_ap_ids) + } + end end) + |> Enum.filter(& &1) conn |> json(reactions) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 897215698..9bfe86704 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -271,6 +271,7 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do pipe_through(:api) + get("/statuses/:id/reactions/:emoji", PleromaAPIController, :emoji_reactions_by) get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by) end diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs index 36868db38..164cfa695 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -96,6 +96,32 @@ test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do result end + test "GET /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) + + result = + conn + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") + |> json_response(200) + + assert result == [] + + {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") + {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + + result = + conn + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") + |> json_response(200) + + [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result + + assert represented_user["id"] == other_user.id + end + test "/api/v1/pleroma/conversations/:id" do user = insert(:user) %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) From 3af6d3f8e27efbe1a048dfd0cd5a5f4f2a8eedc6 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 19 Feb 2020 17:17:05 +0100 Subject: [PATCH 09/12] Emoji Reactions: Add documentation --- CHANGELOG.md | 1 + docs/API/pleroma_api.md | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e838983b..6b0edb1fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,6 +114,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Configuration: `feed.logo` option for tag feed. - Tag feed: `/tags/:tag.rss` - list public statuses by hashtag. - Mastodon API: Add `reacted` property to `emoji_reactions` +- Pleroma API: Add reactions for a single emoji.
### Fixed diff --git a/docs/API/pleroma_api.md b/docs/API/pleroma_api.md index 07e0af5e5..761d5c69c 100644 --- a/docs/API/pleroma_api.md +++ b/docs/API/pleroma_api.md @@ -459,3 +459,16 @@ Emoji reactions work a lot like favourites do. They make it possible to react to {"name": "☕", "count": 1, "me": false, "accounts": [{"id" => "abc..."}]} ] ``` + +## `GET /api/v1/pleroma/statuses/:id/reactions/:emoji` +### Get an object of emoji to account mappings with accounts that reacted to the post for a specific emoji` +* Method: `GET` +* Authentication: optional +* Params: None +* Response: JSON, a list of emoji/account list tuples +* Example Response: +```json +[ + {"name": "😀", "count": 2, "me": true, "accounts": [{"id" => "xyz.."...}, {"id" => "zyx..."}]} +] +``` From 2d5cf0f8cd36d206be2883a5ff29ca9873e0b26d Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 20 Feb 2020 16:44:31 +0100 Subject: [PATCH 10/12] Migrations: Make them not fail for old databases --- .../migrations/20190414125034_migrate_old_bookmarks.exs | 6 +++++- ...90710125158_add_following_address_from_source_data.exs | 8 ++++++-- .../20190711042024_copy_muted_to_muted_notifications.exs | 2 ++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs b/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs index 99102117f..c618ea381 100644 --- a/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs +++ b/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs @@ -17,7 +17,11 @@ def up do Repo.stream(query) |> Enum.each(fn %{id: user_id, bookmarks: bookmarks} -> Enum.each(bookmarks, fn ap_id -> - activity = Activity.get_create_by_object_ap_id(ap_id) + activity = + ap_id + |> Activity.create_by_object_ap_id() + |> Repo.one() + unless is_nil(activity), do: {:ok, _} = Bookmark.create(user_id, activity.id) end) end) diff --git a/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs b/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs index a5170d521..44f9891b1 100644 --- a/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs +++ b/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs @@ -1,7 +1,8 @@ defmodule Pleroma.Repo.Migrations.AddFollowingAddressFromSourceData do - use Ecto.Migration - import Ecto.Query alias Pleroma.User + import Ecto.Query + require Logger + use Ecto.Migration def change do query = @@ -19,6 +20,9 @@ def change do :following_address ]) |> Pleroma.Repo.update() + + user -> + Logger.warn("User #{user.id} / #{user.nickname} does not seem to have source_data") end) end end diff --git a/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs b/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs index fc9bf70ba..bbd502044 100644 --- a/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs +++ b/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs @@ -2,6 +2,8 @@ defmodule Pleroma.Repo.Migrations.CopyMutedToMutedNotifications do use Ecto.Migration def change do + execute("update users set info = '{}' where info is null") + execute( "update users set info = safe_jsonb_set(info, '{muted_notifications}', info->'mutes', true) where local = true" ) From b6bb73f43e31cc252dd3c64a85edd9650ebbf87c Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 20 Feb 2020 15:34:10 -0600 Subject: [PATCH 11/12] Apply database session parameter to improve GIN full text search --- config/config.exs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/config.exs b/config/config.exs index 0eff26653..641b2c867 100644 --- a/config/config.exs +++ b/config/config.exs @@ -617,6 +617,8 @@ config :pleroma, configurable_from_database: false +config :pleroma, Pleroma.Repo, parameters: [gin_fuzzy_search_limit: "500"] + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" From 1ed485ec1da435e32a8a867f1a0b5b9d3624095f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igelj=C3=A4ger?= Date: Fri, 21 Feb 2020 15:30:52 +0000 Subject: [PATCH 12/12] added why doing a vacuum after restoring a backup is so important --- docs/administration/backup.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/administration/backup.md b/docs/administration/backup.md index 685c45128..692aa7368 100644 --- a/docs/administration/backup.md +++ b/docs/administration/backup.md @@ -18,7 +18,9 @@ 6. Run `sudo -Hu postgres pg_restore -d -v -1 ` 7. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. 8. Restart the Pleroma service. - +9. After you've restarted Pleroma, you will notice that postgres will take up more cpu resources than usual. A lot in fact. To fix this you must do a VACUUM ANLAYZE. This can also be done while the instance is still running like so: + $ sudo -u postgres psql pleroma_database_name + pleroma=# VACUUM ANALYZE; [^1]: Prefix with `MIX_ENV=prod` to run it using the production config file. ## Remove