diff --git a/lib/pleroma/web/akkoma_api/controllers/protocol_handler_controller.ex b/lib/pleroma/web/akkoma_api/controllers/protocol_handler_controller.ex index ee0cdf69b..a0a521f5b 100644 --- a/lib/pleroma/web/akkoma_api/controllers/protocol_handler_controller.ex +++ b/lib/pleroma/web/akkoma_api/controllers/protocol_handler_controller.ex @@ -41,13 +41,24 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerController do defp find_and_redirect(%{assigns: %{user: user}} = conn, identifier) do # Remove userinfo if present (username:password@) cleaned = URI.parse("https:" <> identifier) |> Map.merge(%{ userinfo: nil }) |> URI.to_string() - with {:error, _err} <- User.get_or_fetch( cleaned), - [] <- DatabaseSearch.maybe_fetch([], user, cleaned) do + with {:error, _err} <- User.get_or_fetch(cleaned), + [] <- DatabaseSearch.maybe_fetch([], user, cleaned), + [] <- exact_search(cleaned, user) do conn |> json_response(:not_found, "Not Found - #{cleaned}") else {:ok, %User{} = found_user} -> conn |> redirect(to: "/users/#{found_user.id}") + [%User{} = found_user] -> conn |> redirect(to: "/users/#{found_user.id}") + [%Activity{} = found_activity] -> conn |> redirect(to: "/notice/#{found_activity.id}") end end + + defp exact_search(identifier, user) do + case User.search(identifier, limit: 1, for_user: user) do + [%User{:ap_id => ^identifier} = found_user] -> [found_user] + [%User{:uri => ^identifier} = found_user] -> [found_user] + _ -> [] + end + end end diff --git a/test/pleroma/web/akkoma_api/protocol_handler_controller_test.exs b/test/pleroma/web/akkoma_api/protocol_handler_controller_test.exs index 556b94b74..5857dece8 100644 --- a/test/pleroma/web/akkoma_api/protocol_handler_controller_test.exs +++ b/test/pleroma/web/akkoma_api/protocol_handler_controller_test.exs @@ -6,6 +6,38 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerControllerTest do import Pleroma.Factory + setup do + Tesla.Mock.mock(fn + %{method: :get, url: "https://mastodon.social/users/emelie/statuses/101849165031453009"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/status.emelie.json") + } + %{method: :get, url: "https://mastodon.social/users/emelie"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/emelie.json") + } + %{method: :get, url: "https://mastodon.social/@emelie"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: File.read!("test/fixtures/tesla_mock/emelie.json") + } + %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "mastodon.social") + |> String.replace("{{nickname}}", "emelie") + } + end) + end + describe "GET /.well-known/protocol-handler" do test "should return bad_request when missing `target`" do %{conn: conn} = oauth_access([]) @@ -70,29 +102,7 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerControllerTest do test "should return redirect for unauthed user when target is local AP ID for note activity" do clear_config([Pleroma.Web.Endpoint, :url, :host], "mastodon.social") - Tesla.Mock.mock(fn - %{method: :get, url: "https://mastodon.social/users/emelie/statuses/101849165031453009"} -> - %Tesla.Env{ - status: 200, - headers: [{"content-type", "application/activity+json"}], - body: File.read!("test/fixtures/tesla_mock/status.emelie.json") - } - %{method: :get, url: "https://mastodon.social/users/emelie"} -> - %Tesla.Env{ - status: 200, - headers: [{"content-type", "application/activity+json"}], - body: File.read!("test/fixtures/tesla_mock/emelie.json") - } - %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} -> - %Tesla.Env{ - status: 200, - headers: [{"content-type", "application/activity+json"}], - body: - File.read!("test/fixtures/users_mock/masto_featured.json") - |> String.replace("{{domain}}", "mastodon.social") - |> String.replace("{{nickname}}", "emelie") - } - end) + clear_config([Pleroma.Web.Endpoint, :url, :host], "sub.example.com") %{conn: conn} = oauth_access(["read:search"]) @@ -119,6 +129,24 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerControllerTest do assert resp =~ "" end + test "should return redirect for authed user when target is URL for user" do + %{conn: conn} = oauth_access(["read:search"]) + remote_user = insert(:user, %{ + nickname: "emelie@mastodon.social", + local: false, + ap_id: "https://mastodon.social/users/emelie", + uri: "https://mastodon.social/@emelie", + }) + + resp = + conn + |> get("/api/v1/akkoma/protocol-handler?target=web%2Bap%3A%2F%2Fmastodon.social/%40emelie") + |> html_response(302) + + assert resp =~ "You are being" + assert resp =~ "" + end + test "should return redirect for authed user when target is AP ID for user, stripping userinfo" do %{conn: conn} = oauth_access(["read:search"]) remote_user = insert(:user, %{nickname: "akkoma@ihatebeinga.live", local: false, ap_id: "https://ihatebeinga.live/users/akkoma"}) @@ -133,29 +161,6 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerControllerTest do end test "should return redirect for authed user when target is AP ID for note activity" do - Tesla.Mock.mock(fn - %{method: :get, url: "https://mastodon.social/users/emelie/statuses/101849165031453009"} -> - %Tesla.Env{ - status: 200, - headers: [{"content-type", "application/activity+json"}], - body: File.read!("test/fixtures/tesla_mock/status.emelie.json") - } - %{method: :get, url: "https://mastodon.social/users/emelie"} -> - %Tesla.Env{ - status: 200, - headers: [{"content-type", "application/activity+json"}], - body: File.read!("test/fixtures/tesla_mock/emelie.json") - } - %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} -> - %Tesla.Env{ - status: 200, - headers: [{"content-type", "application/activity+json"}], - body: - File.read!("test/fixtures/users_mock/masto_featured.json") - |> String.replace("{{domain}}", "mastodon.social") - |> String.replace("{{nickname}}", "emelie") - } - end) %{conn: conn} = oauth_access(["read:search"]) resp =