Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into lazarus

This commit is contained in:
Lain Soykaf 2025-08-27 15:27:37 +04:00
commit a5dbf8dead
15 changed files with 118 additions and 12 deletions

View file

@ -290,7 +290,7 @@ stop_review_app:
amd64:
stage: release
image:
name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011
name: hexpm/elixir-amd64:1.17.3-erlang-27.3.4.2-ubuntu-noble-20250716
only: &release-only
- stable@pleroma/pleroma
- develop@pleroma/pleroma
@ -317,7 +317,7 @@ amd64:
VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS
DEBIAN_FRONTEND: noninteractive
before_script: &before-release
- apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev git
- apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev git build-essential
- echo "import Config" > config/prod.secret.exs
- mix local.hex --force
- mix local.rebar --force
@ -333,7 +333,7 @@ amd64-musl:
artifacts: *release-artifacts
only: *release-only
image:
name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-alpine-3.17.9
name: hexpm/elixir-amd64:1.17.3-erlang-27.3.4.2-alpine-3.22.1
tags:
- amd64
cache: *release-cache
@ -377,7 +377,7 @@ arm64:
tags:
- arm
image:
name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011
name: hexpm/elixir-arm64:1.17.3-erlang-27.3.4.2-ubuntu-noble-20250716
cache: *release-cache
variables: *release-variables
before_script: *before-release
@ -390,7 +390,7 @@ arm64-musl:
tags:
- arm
image:
name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-alpine-3.17.9
name: hexpm/elixir-arm64:1.17.3-erlang-27.3.4.2-alpine-3.22.1
cache: *release-cache
variables: *release-variables
before_script: *before-release-musl

View file

@ -1,10 +1,10 @@
# https://hub.docker.com/r/hexpm/elixir/tags
ARG ELIXIR_IMG=hexpm/elixir
ARG ELIXIR_VER=1.14.5
ARG ERLANG_VER=25.3.2.14
ARG ELIXIR_VER=1.17.3
ARG ERLANG_VER=26.2.5.6
ARG ALPINE_VER=3.17.9
FROM ${ELIXIR_IMG}:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} as build
FROM ${ELIXIR_IMG}:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} AS build
COPY . .
@ -15,6 +15,7 @@ RUN apk add git gcc g++ musl-dev make cmake file-dev vips-dev &&\
echo "import Config" > config/prod.secret.exs &&\
mix local.hex --force &&\
mix local.rebar --force &&\
mix deps.clean --all &&\
mix deps.get --only prod &&\
mkdir release &&\
mix release --path release

View file

@ -0,0 +1 @@
Admin API: Fixed self-revocation vulnerability where admins could accidentally revoke their own admin status via the single-user permission endpoint

View file

@ -0,0 +1 @@
Update Dockerfile to use Elixir 1.17.3, Erlang 26.2.5.6, and Alpine 3.17.9 to match CI release builds

View file

@ -0,0 +1 @@
Fix ModerationLog FunctionClauseError for unknown actions

View file

@ -0,0 +1 @@
Add only_reblogs parameter to account statuses API for filtering to show only reblogs/reposts

View file

@ -88,6 +88,7 @@ The `id` parameter can also be the `nickname` of the user. This only works in th
- `only_media`: include only statuses with media attached
- `with_muted`: include statuses/reactions from muted accounts
- `exclude_reblogs`: exclude reblogs
- `only_reblogs`: include only reblogs
- `exclude_replies`: exclude replies
- `exclude_visibilities`: exclude visibilities

View file

@ -575,6 +575,12 @@ defmodule Pleroma.ModerationLog do
"@#{actor_nickname} requested account backup for @#{user_nickname}"
end
def get_log_entry_message(%ModerationLog{data: data}) do
actor_name = get_in(data, ["actor", "nickname"]) || "unknown"
action = data["action"] || "unknown"
"@#{actor_name} performed action #{action}"
end
defp nicknames_to_string(nicknames) do
nicknames
|> Enum.map(&"@#{&1}")

View file

@ -1065,6 +1065,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
from(activity in query, where: fragment("?->>'type' != 'Announce'", activity.data))
end
defp restrict_reblogs(query, %{only_reblogs: true}) do
from(activity in query, where: fragment("?->>'type' = 'Announce'", activity.data))
end
defp restrict_reblogs(query, _), do: query
defp restrict_muted(query, %{with_muted: true}), do: query

View file

@ -240,6 +240,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
render_error(conn, :not_found, "No such permission_group")
end
def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
render_error(conn, :forbidden, "You can't revoke your own admin status.")
end
def right_delete(
%{assigns: %{user: admin}} = conn,
%{
@ -265,10 +269,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
json(conn, fields)
end
def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
render_error(conn, :forbidden, "You can't revoke your own admin status.")
end
@doc "Get a password reset token (base64 string) for given nickname"
def get_password_reset(conn, %{"nickname" => nickname}) do
(%User{local: true} = user) = User.get_cached_by_nickname(nickname)

View file

@ -143,6 +143,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
"Include statuses from muted accounts."
),
Operation.parameter(:exclude_reblogs, :query, BooleanLike.schema(), "Exclude reblogs"),
Operation.parameter(
:only_reblogs,
:query,
BooleanLike.schema(),
"Include only reblogs"
),
Operation.parameter(:exclude_replies, :query, BooleanLike.schema(), "Exclude replies"),
Operation.parameter(
:exclude_visibilities,

View file

@ -308,4 +308,37 @@ defmodule Pleroma.ModerationLogTest do
assert log.data["message"] == "@#{moderator.nickname} deleted status ##{note.id}"
end
end
describe "get_log_entry_message/1" do
setup do
moderator = insert(:user, is_moderator: true)
[moderator: moderator]
end
test "handles unknown action types gracefully", %{moderator: moderator} do
log_entry = %ModerationLog{
data: %{
"actor" => %{"nickname" => moderator.nickname},
"action" => "unknown_action",
"some_data" => "test_value"
}
}
assert ModerationLog.get_log_entry_message(log_entry) =~ moderator.nickname
assert ModerationLog.get_log_entry_message(log_entry) =~ "unknown_action"
end
test "handles malformed log entries gracefully" do
log_entry = %ModerationLog{
data: %{
"action" => "force_password_reset"
# Missing "actor" and "subject" fields
}
}
message = ModerationLog.get_log_entry_message(log_entry)
assert is_binary(message)
assert message =~ "force_password_reset"
end
end
end

View file

@ -1270,6 +1270,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert activity == expected_activity
end
test "includes only reblogs on request" do
user = insert(:user)
{:ok, _} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
{:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
[activity] = ActivityPub.fetch_user_activities(user, nil, %{only_reblogs: true})
assert activity == expected_activity
end
describe "irreversible filters" do
setup do
user = insert(:user)

View file

@ -321,6 +321,36 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{user_two.nickname}"
end
test "/:right DELETE, admin cannot revoke their own admin status (single)", %{
admin: admin,
conn: conn
} do
conn =
conn
|> put_req_header("accept", "application/json")
|> delete("/api/pleroma/admin/users/#{admin.nickname}/permission_group/admin")
assert json_response(conn, 403) == %{"error" => "You can't revoke your own admin status."}
end
test "/:right DELETE, admin cannot revoke their own admin status (multiple)", %{
admin: admin,
conn: conn
} do
user = insert(:user, is_admin: true)
conn =
conn
|> put_req_header("accept", "application/json")
|> delete("/api/pleroma/admin/users/permission_group/admin", %{
nicknames: [admin.nickname, user.nickname]
})
assert json_response(conn, 403) == %{
"error" => "You can't revoke your own admin/moderator status."
}
end
end
describe "/api/pleroma/admin/users/:nickname/password_reset" do

View file

@ -469,6 +469,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
end
test "gets only a user's reblogs", %{user: user, conn: conn} do
{:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"})
{:ok, %{id: reblog_id}} = CommonAPI.repeat(post_id, user)
conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_reblogs=true")
assert [%{"id" => ^reblog_id}] = json_response_and_validate_schema(conn, 200)
conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_reblogs=1")
assert [%{"id" => ^reblog_id}] = json_response_and_validate_schema(conn, 200)
end
test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
{:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "#hashtag"})
{:ok, _post} = CommonAPI.post(user, %{status: "hashtag"})