fallback to User.search to support profile URI

Use exact search to only match on ap_id or uri
This commit is contained in:
smitten 2023-07-28 15:37:13 -04:00
parent 4ac6fbe6c9
commit 208d2a6e0d
Signed by: smitten
GPG key ID: 1DDD22F13552A07A
2 changed files with 64 additions and 48 deletions

View file

@ -41,13 +41,24 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerController do
defp find_and_redirect(%{assigns: %{user: user}} = conn, identifier) do defp find_and_redirect(%{assigns: %{user: user}} = conn, identifier) do
# Remove userinfo if present (username:password@) # Remove userinfo if present (username:password@)
cleaned = URI.parse("https:" <> identifier) |> Map.merge(%{ userinfo: nil }) |> URI.to_string() cleaned = URI.parse("https:" <> identifier) |> Map.merge(%{ userinfo: nil }) |> URI.to_string()
with {:error, _err} <- User.get_or_fetch( cleaned), with {:error, _err} <- User.get_or_fetch(cleaned),
[] <- DatabaseSearch.maybe_fetch([], user, cleaned) do [] <- DatabaseSearch.maybe_fetch([], user, cleaned),
[] <- exact_search(cleaned, user) do
conn |> json_response(:not_found, "Not Found - #{cleaned}") conn |> json_response(:not_found, "Not Found - #{cleaned}")
else else
{:ok, %User{} = found_user} -> conn |> redirect(to: "/users/#{found_user.id}") {: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}") [%Activity{} = found_activity] -> conn |> redirect(to: "/notice/#{found_activity.id}")
end end
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 end

View file

@ -6,6 +6,38 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerControllerTest do
import Pleroma.Factory 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 describe "GET /.well-known/protocol-handler" do
test "should return bad_request when missing `target`" do test "should return bad_request when missing `target`" do
%{conn: conn} = oauth_access([]) %{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 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") 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") clear_config([Pleroma.Web.Endpoint, :url, :host], "sub.example.com")
%{conn: conn} = oauth_access(["read:search"]) %{conn: conn} = oauth_access(["read:search"])
@ -119,6 +129,24 @@ defmodule Pleroma.Web.AkkomaAPI.ProtocolHandlerControllerTest do
assert resp =~ "<a href=\"/users/#{remote_user.id}\">" assert resp =~ "<a href=\"/users/#{remote_user.id}\">"
end 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 =~ "<a href=\"/users/#{remote_user.id}\">"
end
test "should return redirect for authed user when target is AP ID for user, stripping userinfo" do test "should return redirect for authed user when target is AP ID for user, stripping userinfo" do
%{conn: conn} = oauth_access(["read:search"]) %{conn: conn} = oauth_access(["read:search"])
remote_user = insert(:user, %{nickname: "akkoma@ihatebeinga.live", local: false, ap_id: "https://ihatebeinga.live/users/akkoma"}) 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 end
test "should return redirect for authed user when target is AP ID for note activity" do 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"]) %{conn: conn} = oauth_access(["read:search"])
resp = resp =