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 =