- data = Base.decode64!(parsed["data"])
- uuid = UUID.generate
- upload_folder = Path.join(upload_path(), uuid)
- File.mkdir_p!(upload_folder)
- filename = Base.encode16(:crypto.hash(:sha256, data)) <> ".#{parsed["filetype"]}"
- result_file = Path.join(upload_folder, filename)
-
- File.write!(result_file, data)
-
- content_type = "image/#{parsed["filetype"]}"
-
- %{
- "type" => "Image",
- "url" => [%{
- "type" => "Link",
- "mediaType" => content_type,
- "href" => url_for(Path.join(uuid, :cow_uri.urlencode(filename)))
- }],
- "name" => filename,
- "uuid" => uuid
- }
+ data = Base.decode64!(parsed["data"], ignore: :whitespace)
+ hash = String.downcase(Base.encode16(:crypto.hash(:sha256, data)))
+
+ with :ok <- check_binary_size(data, opts.size_limit),
+ tmp_path <- tempfile_for_image(data),
+ {:ok, content_type, name} <-
+ Pleroma.MIME.bin_mime_type(data, hash <> "." <> parsed["filetype"]) do
+ {:ok,
+ %__MODULE__{
+ id: UUID.generate(),
+ name: name,
+ tempfile: tmp_path,
+ content_type: content_type
+ }}
+ end
+ end
+
+ # For Mix.Tasks.MigrateLocalUploads
+ defp prepare_upload(upload = %__MODULE__{tempfile: path}, _opts) do
+ with {:ok, content_type} <- Pleroma.MIME.file_mime_type(path) do
+ {:ok, %__MODULE__{upload | content_type: content_type}}
+ end
+ end
+
+ defp check_binary_size(binary, size_limit)
+ when is_integer(size_limit) and size_limit > 0 and byte_size(binary) >= size_limit do
+ {:error, :file_too_large}
+ end
+
+ defp check_binary_size(_, _), do: :ok
+
+ defp check_file_size(path, size_limit) when is_integer(size_limit) and size_limit > 0 do
+ with {:ok, %{size: size}} <- File.stat(path),
+ true <- size <= size_limit do
+ :ok
+ else
+ false -> {:error, :file_too_large}
+ error -> error
+ end
+ end
+
+ defp check_file_size(_, _), do: :ok
+
+ # Creates a tempfile using the Plug.Upload Genserver which cleans them up
+ # automatically.
+ defp tempfile_for_image(data) do
+ {:ok, tmp_path} = Plug.Upload.random_file("profile_pics")
+ {:ok, tmp_file} = File.open(tmp_path, [:write, :raw, :binary])
+ IO.binwrite(tmp_file, data)
+
+ tmp_path