Harden public asset endpoint against invalid payloads

Closes #143
This commit is contained in:
Claudio Ortolina
2026-03-30 14:56:40 +01:00
parent 45fd414f1b
commit 92a36b915a
4 changed files with 95 additions and 18 deletions
+13 -7
View File
@@ -22,14 +22,17 @@ defmodule MusicLibrary.Assets.Image do
[:music_library, :assets, :image, :resize],
%{},
fn ->
{:ok, thumb} = Operation.thumbnail_buffer(cover_data, size)
result = Image.write_to_buffer(thumb, extension(format))
{result, %{}}
with {:ok, thumb} <- Operation.thumbnail_buffer(cover_data, size),
{:ok, _binary} = result <- Image.write_to_buffer(thumb, extension(format)) do
{result, %{}}
else
{:error, _reason} = error -> {error, %{}}
end
end
)
end
@spec convert(binary(), String.t(), String.t()) :: {:ok, binary()}
@spec convert(binary(), String.t(), String.t()) :: {:ok, binary()} | {:error, term()}
def convert(cover_data, data_format, target_format) do
if data_format == target_format do
{:ok, cover_data}
@@ -38,9 +41,12 @@ defmodule MusicLibrary.Assets.Image do
[:music_library, :assets, :image, :convert],
%{},
fn ->
{:ok, image} = Image.new_from_buffer(cover_data)
result = Image.write_to_buffer(image, extension(target_format))
{result, %{}}
with {:ok, image} <- Image.new_from_buffer(cover_data),
{:ok, _binary} = result <- Image.write_to_buffer(image, extension(target_format)) do
{result, %{}}
else
{:error, _reason} = error -> {error, %{}}
end
end
)
end
+24
View File
@@ -25,6 +25,30 @@ defmodule MusicLibrary.Assets.Transform do
|> Base.url_encode64(padding: false)
end
@doc """
Decodes a Base64-encoded JSON payload into a transform struct.
Returns `{:error, :invalid_payload}` if the payload is not valid Base64 or JSON.
iex> alias MusicLibrary.Assets.Transform
iex> payload = "eyJoYXNoIjoiYWJjMTIzIiwid2lkdGgiOjMwMH0"
iex> Transform.decode(payload)
{:ok, %Transform{hash: "abc123", width: 300}}
iex> alias MusicLibrary.Assets.Transform
iex> Transform.decode("!!!invalid")
{:error, :invalid_payload}
"""
@spec decode(payload()) :: {:ok, t()} | {:error, :invalid_payload}
def decode(payload) do
with {:ok, decoded} <- Base.url_decode64(payload, padding: false),
{:ok, params} when is_map(params) <- JSON.decode(decoded) do
{:ok, struct!(__MODULE__, %{hash: params["hash"], width: params["width"]})}
else
_ -> {:error, :invalid_payload}
end
end
@doc """
iex> alias MusicLibrary.Assets.Transform
iex> payload = "eyJoYXNoIjoiYWJjMTIzIiwid2lkdGgiOjMwMH0"