Merge branch 'security/fav-reblog-access-control' into 'develop'
Mastodon API: Respect post privacy in favourited/reblogged endpoints See merge request pleroma/pleroma!1667
This commit is contained in:
commit
4264c4b7e5
3 changed files with 56 additions and 2 deletions
|
@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Security
|
### Security
|
||||||
- OStatus: eliminate the possibility of a protocol downgrade attack.
|
- OStatus: eliminate the possibility of a protocol downgrade attack.
|
||||||
- OStatus: prevent following locked accounts, bypassing the approval process.
|
- OStatus: prevent following locked accounts, bypassing the approval process.
|
||||||
|
- Mastodon API: respect post privacy in `/api/v1/statuses/:id/{favourited,reblogged}_by`
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- **Breaking:** GNU Social API with Qvitter extensions support
|
- **Breaking:** GNU Social API with Qvitter extensions support
|
||||||
|
|
|
@ -842,6 +842,7 @@ def get_mascot(%{assigns: %{user: user}} = conn, _params) do
|
||||||
|
|
||||||
def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||||
|
{:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
|
||||||
%Object{data: %{"likes" => likes}} <- Object.normalize(activity) do
|
%Object{data: %{"likes" => likes}} <- Object.normalize(activity) do
|
||||||
q = from(u in User, where: u.ap_id in ^likes)
|
q = from(u in User, where: u.ap_id in ^likes)
|
||||||
|
|
||||||
|
@ -853,12 +854,14 @@ def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
|> put_view(AccountView)
|
|> put_view(AccountView)
|
||||||
|> render("accounts.json", %{for: user, users: users, as: :user})
|
|> render("accounts.json", %{for: user, users: users, as: :user})
|
||||||
else
|
else
|
||||||
|
{:visible, false} -> {:error, :not_found}
|
||||||
_ -> json(conn, [])
|
_ -> json(conn, [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||||
|
{:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
|
||||||
%Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do
|
%Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do
|
||||||
q = from(u in User, where: u.ap_id in ^announces)
|
q = from(u in User, where: u.ap_id in ^announces)
|
||||||
|
|
||||||
|
@ -870,6 +873,7 @@ def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
|> put_view(AccountView)
|
|> put_view(AccountView)
|
||||||
|> render("accounts.json", %{for: user, users: users, as: :user})
|
|> render("accounts.json", %{for: user, users: users, as: :user})
|
||||||
else
|
else
|
||||||
|
{:visible, false} -> {:error, :not_found}
|
||||||
_ -> json(conn, [])
|
_ -> json(conn, [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3698,7 +3698,7 @@ test "returns 404 when poll is private and not available for user", %{conn: conn
|
||||||
build_conn()
|
build_conn()
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|
|
||||||
[conn: conn, activity: activity]
|
[conn: conn, activity: activity, user: user]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns users who have favorited the status", %{conn: conn, activity: activity} do
|
test "returns users who have favorited the status", %{conn: conn, activity: activity} do
|
||||||
|
@ -3758,6 +3758,32 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti
|
||||||
[%{"id" => id}] = response
|
[%{"id" => id}] = response
|
||||||
assert id == other_user.id
|
assert id == other_user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "requires authentification for private posts", %{conn: conn, user: user} do
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
CommonAPI.post(user, %{
|
||||||
|
"status" => "@#{other_user.nickname} wanna get some #cofe together?",
|
||||||
|
"visibility" => "direct"
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> assign(:user, nil)
|
||||||
|
|> get("/api/v1/statuses/#{activity.id}/favourited_by")
|
||||||
|
|> json_response(404)
|
||||||
|
|
||||||
|
response =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, other_user)
|
||||||
|
|> get("/api/v1/statuses/#{activity.id}/favourited_by")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
[%{"id" => id}] = response
|
||||||
|
assert id == other_user.id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /api/v1/statuses/:id/reblogged_by" do
|
describe "GET /api/v1/statuses/:id/reblogged_by" do
|
||||||
|
@ -3769,7 +3795,7 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti
|
||||||
build_conn()
|
build_conn()
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|
|
||||||
[conn: conn, activity: activity]
|
[conn: conn, activity: activity, user: user]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
|
test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
|
||||||
|
@ -3829,6 +3855,29 @@ test "does not fail on an unauthenticated request", %{conn: conn, activity: acti
|
||||||
[%{"id" => id}] = response
|
[%{"id" => id}] = response
|
||||||
assert id == other_user.id
|
assert id == other_user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "requires authentification for private posts", %{conn: conn, user: user} do
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
CommonAPI.post(user, %{
|
||||||
|
"status" => "@#{other_user.nickname} wanna get some #cofe together?",
|
||||||
|
"visibility" => "direct"
|
||||||
|
})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> assign(:user, nil)
|
||||||
|
|> get("/api/v1/statuses/#{activity.id}/reblogged_by")
|
||||||
|
|> json_response(404)
|
||||||
|
|
||||||
|
response =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, other_user)
|
||||||
|
|> get("/api/v1/statuses/#{activity.id}/reblogged_by")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert [] == response
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "POST /auth/password, with valid parameters" do
|
describe "POST /auth/password, with valid parameters" do
|
||||||
|
|
Loading…
Reference in a new issue