fix(admin-api): reject explicit empty passwords

This commit is contained in:
Lain Soykaf 2026-07-24 22:52:23 +04:00
commit 836f4a2d69
No known key found for this signature in database
4 changed files with 25 additions and 11 deletions

View file

@ -80,7 +80,7 @@ The `/api/v1/pleroma/admin/*` path is backwards compatible with `/api/pleroma/ad
{ {
`nickname`, `nickname`,
`email`, `email`,
`password` (optional) `password` (optional; when provided, must not be empty)
} }
] ]
- Response: Array of user objects. When a user is created without a `password`, `data` - Response: Array of user objects. When a user is created without a `password`, `data`

View file

@ -153,7 +153,7 @@ defmodule Pleroma.Web.AdminAPI.UserController do
_ _
) do ) do
conn = conn =
if Enum.any?(users, fn user -> Map.get(user, :password) in ["", nil] end) do if Enum.any?(users, fn user -> not Map.has_key?(user, :password) end) do
put_private(conn, :skip_idempotency_cache, true) put_private(conn, :skip_idempotency_cache, true)
else else
conn conn
@ -162,15 +162,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
multi = multi =
users users
|> Enum.map(fn %{nickname: nickname, email: email} = attrs -> |> Enum.map(fn %{nickname: nickname, email: email} = attrs ->
passwordless? = Map.get(attrs, :password) in ["", nil] {password, passwordless?} =
case Map.fetch(attrs, :password) do
{:ok, password} ->
{password, false}
password = :error ->
case Map.get(attrs, :password) do {:crypto.strong_rand_bytes(16) |> Base.encode64(), true}
password when is_binary(password) and password != "" ->
password
_ ->
:crypto.strong_rand_bytes(16) |> Base.encode64()
end end
user_data = %{ user_data = %{

View file

@ -86,7 +86,8 @@ defmodule Pleroma.Web.ApiSpec.Admin.UserOperation do
type: :string, type: :string,
description: description:
"Optional. When omitted, a `password_reset_link` is returned, " <> "Optional. When omitted, a `password_reset_link` is returned, " <>
"allowing the user to set their own password." "allowing the user to set their own password. When provided, " <>
"it must not be empty."
} }
}, },
required: [:nickname, :email] required: [:nickname, :email]

View file

@ -208,6 +208,21 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do
refute Map.has_key?(account2["data"], "password_reset_link") refute Map.has_key?(account2["data"], "password_reset_link")
end end
test "Explicit empty passwords return a conflict", %{conn: conn} do
conn =
conn
|> put_req_header("accept", "application/json")
|> put_req_header("content-type", "application/json")
|> post("/api/pleroma/admin/users", %{
"users" => [
%{"nickname" => "lain", "email" => "lain@example.org", "password" => ""}
]
})
assert [%{"error" => "password can't be blank"}] = json_response(conn, 409)
refute User.get_by_nickname("lain")
end
test "Password reset token failures roll back the user batch", %{conn: conn} do test "Password reset token failures roll back the user batch", %{conn: conn} do
with_mock Pleroma.PasswordResetToken, [:passthrough], with_mock Pleroma.PasswordResetToken, [:passthrough],
create_token: fn user -> create_token: fn user ->