CommonAPI: Forbid disallowed status (un)muting and unpinning
When a user tried to unpin a status not belonging to them, a full MastoAPI response was sent back even if status was not visible to them. Ditto with (un)mutting except ownership.
This commit is contained in:
parent
f914748510
commit
426535bc38
4 changed files with 101 additions and 6 deletions
|
|
@ -250,7 +250,19 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
|
|||
example: %{
|
||||
"error" => "Record not found"
|
||||
}
|
||||
})
|
||||
}),
|
||||
422 =>
|
||||
Operation.response(
|
||||
"Unprocessable Entity",
|
||||
"application/json",
|
||||
%Schema{
|
||||
allOf: [ApiError],
|
||||
title: "Unprocessable Entity",
|
||||
example: %{
|
||||
"error" => "Someone else's status cannot be unpinned"
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
@ -325,7 +337,17 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
|
|||
],
|
||||
responses: %{
|
||||
200 => status_response(),
|
||||
400 => Operation.response("Error", "application/json", ApiError)
|
||||
400 => Operation.response("Error", "application/json", ApiError),
|
||||
404 =>
|
||||
Operation.response(
|
||||
"Unprocessable Entity",
|
||||
"application/json",
|
||||
%Schema{
|
||||
allOf: [ApiError],
|
||||
title: "Error",
|
||||
example: %{"error" => "Record not found"}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
@ -341,7 +363,17 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
|
|||
parameters: [id_param()],
|
||||
responses: %{
|
||||
200 => status_response(),
|
||||
400 => Operation.response("Error", "application/json", ApiError)
|
||||
400 => Operation.response("Error", "application/json", ApiError),
|
||||
404 =>
|
||||
Operation.response(
|
||||
"Error",
|
||||
"application/json",
|
||||
%Schema{
|
||||
allOf: [ApiError],
|
||||
title: "Error",
|
||||
example: %{"error" => "Record not found"}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -554,6 +554,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
@spec unpin(String.t(), User.t()) :: {:ok, Activity.t()} | Pipeline.errors()
|
||||
def unpin(id, user) do
|
||||
with %Activity{} = activity <- create_activity_by_id(id),
|
||||
true <- activity_belongs_to_actor(activity, user.ap_id),
|
||||
{:ok, unpin_data, _} <- Builder.unpin(user, activity.object),
|
||||
{:ok, _unpin, _} <-
|
||||
Pipeline.common_pipeline(unpin_data,
|
||||
|
|
@ -570,7 +571,8 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
def add_mute(activity, user, params \\ %{}) do
|
||||
expires_in = Map.get(params, :expires_in, 0)
|
||||
|
||||
with {:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]),
|
||||
with true <- Visibility.visible_for_user?(activity, user),
|
||||
{:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]),
|
||||
_ <- Pleroma.Notification.mark_context_as_read(user, activity.data["context"]) do
|
||||
if expires_in > 0 do
|
||||
Pleroma.Workers.MuteExpireWorker.new(
|
||||
|
|
@ -583,13 +585,18 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
{:ok, activity}
|
||||
else
|
||||
{:error, _} -> {:error, dgettext("errors", "conversation is already muted")}
|
||||
false -> {:error, :visibility_error}
|
||||
end
|
||||
end
|
||||
|
||||
@spec remove_mute(Activity.t(), User.t()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def remove_mute(%Activity{} = activity, %User{} = user) do
|
||||
ThreadMute.remove_mute(user.id, activity.data["context"])
|
||||
{:ok, activity}
|
||||
if Visibility.visible_for_user?(activity, user) do
|
||||
ThreadMute.remove_mute(user.id, activity.data["context"])
|
||||
{:ok, activity}
|
||||
else
|
||||
{:error, :visibility_error}
|
||||
end
|
||||
end
|
||||
|
||||
@spec remove_mute(String.t(), String.t()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
|
|
|
|||
|
|
@ -413,8 +413,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|
|||
conn,
|
||||
_
|
||||
) do
|
||||
# CommonAPI already checks whether user can unpin
|
||||
with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do
|
||||
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
|
||||
else
|
||||
{:error, :ownership_error} ->
|
||||
{:error, :unprocessable_entity, "Someone else's status cannot be unpinned"}
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -462,8 +469,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|
|||
_
|
||||
) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
# CommonAPI already checks whether user is allowed to mute
|
||||
{:ok, activity} <- CommonAPI.add_mute(activity, user, params) do
|
||||
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
|
||||
else
|
||||
{:error, :visibility_error} ->
|
||||
{:error, :not_found, "Record not found"}
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -476,8 +490,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|
|||
_
|
||||
) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
# CommonAPI already checks whether user is allowed to unmute
|
||||
{:ok, activity} <- CommonAPI.remove_mute(activity, user) do
|
||||
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
|
||||
else
|
||||
{:error, :visibility_error} ->
|
||||
{:error, :not_found, "Record not found"}
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1769,6 +1769,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
|> json_response_and_validate_schema(404) == %{"error" => "Record not found"}
|
||||
end
|
||||
|
||||
test "/unpin: returns 422 error when activity not owned by user", %{activity: activity} do
|
||||
%{conn: conn} = oauth_access(["write:accounts"])
|
||||
|
||||
assert conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses/#{activity.id}/unpin")
|
||||
|> json_response_and_validate_schema(422) == %{
|
||||
"error" => "Someone else's status cannot be unpinned"
|
||||
}
|
||||
end
|
||||
|
||||
test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
|
||||
{:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
|
||||
|
||||
|
|
@ -1977,6 +1988,30 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
|> post("/api/v1/statuses/#{activity.id}/unmute")
|
||||
|> json_response_and_validate_schema(200)
|
||||
end
|
||||
|
||||
test "cannot mute not visible conversation", %{user: user} do
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "Invisible!", visibility: "private"})
|
||||
%{conn: conn} = oauth_access(["write:mutes"])
|
||||
|
||||
assert conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses/#{activity.id}/mute")
|
||||
|> json_response_and_validate_schema(404) == %{
|
||||
"error" => "Record not found"
|
||||
}
|
||||
end
|
||||
|
||||
test "cannot unmute not visible conversation", %{user: user} do
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "Invisible!", visibility: "private"})
|
||||
%{conn: conn} = oauth_access(["write:mutes"])
|
||||
|
||||
assert conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses/#{activity.id}/unmute")
|
||||
|> json_response_and_validate_schema(404) == %{
|
||||
"error" => "Record not found"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue