diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/application.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/mime.ex | 120 | ||||
| -rw-r--r-- | lib/pleroma/upload.ex | 19 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub_controller.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/media_controller.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/pleroma_api/controllers/account_controller.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex | 10 | 
7 files changed, 25 insertions, 133 deletions
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 958e32db2..301b4e273 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -95,6 +95,7 @@ defmodule Pleroma.Application do          [            Pleroma.Stats,            Pleroma.JobQueueMonitor, +          {Majic.Pool, [name: Pleroma.MajicPool, pool_size: Config.get([:majic_pool, :size], 2)]},            {Oban, Config.get(Oban)}          ] ++          task_children(@env) ++ diff --git a/lib/pleroma/mime.ex b/lib/pleroma/mime.ex deleted file mode 100644 index 6ee055f50..000000000 --- a/lib/pleroma/mime.ex +++ /dev/null @@ -1,120 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.MIME do -  @moduledoc """ -  Returns the mime-type of a binary and optionally a normalized file-name. -  """ -  @default "application/octet-stream" -  @read_bytes 35 - -  @spec file_mime_type(String.t(), String.t()) :: -          {:ok, content_type :: String.t(), filename :: String.t()} | {:error, any()} | :error -  def file_mime_type(path, filename) do -    with {:ok, content_type} <- file_mime_type(path), -         filename <- fix_extension(filename, content_type) do -      {:ok, content_type, filename} -    end -  end - -  @spec file_mime_type(String.t()) :: {:ok, String.t()} | {:error, any()} | :error -  def file_mime_type(filename) do -    File.open(filename, [:read], fn f -> -      check_mime_type(IO.binread(f, @read_bytes)) -    end) -  end - -  def bin_mime_type(binary, filename) do -    with {:ok, content_type} <- bin_mime_type(binary), -         filename <- fix_extension(filename, content_type) do -      {:ok, content_type, filename} -    end -  end - -  @spec bin_mime_type(binary()) :: {:ok, String.t()} | :error -  def bin_mime_type(<<head::binary-size(@read_bytes), _::binary>>) do -    {:ok, check_mime_type(head)} -  end - -  def bin_mime_type(_), do: :error - -  def mime_type(<<_::binary>>), do: {:ok, @default} - -  defp fix_extension(filename, content_type) do -    parts = String.split(filename, ".") - -    new_filename = -      if length(parts) > 1 do -        Enum.drop(parts, -1) |> Enum.join(".") -      else -        Enum.join(parts) -      end - -    cond do -      content_type == "application/octet-stream" -> -        filename - -      ext = List.first(MIME.extensions(content_type)) -> -        new_filename <> "." <> ext - -      true -> -        Enum.join([new_filename, String.split(content_type, "/") |> List.last()], ".") -    end -  end - -  defp check_mime_type(<<0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, _::binary>>) do -    "image/png" -  end - -  defp check_mime_type(<<0x47, 0x49, 0x46, 0x38, _, 0x61, _::binary>>) do -    "image/gif" -  end - -  defp check_mime_type(<<0xFF, 0xD8, 0xFF, _::binary>>) do -    "image/jpeg" -  end - -  defp check_mime_type(<<0x1A, 0x45, 0xDF, 0xA3, _::binary>>) do -    "video/webm" -  end - -  defp check_mime_type(<<0x00, 0x00, 0x00, _, 0x66, 0x74, 0x79, 0x70, _::binary>>) do -    "video/mp4" -  end - -  defp check_mime_type(<<0x49, 0x44, 0x33, _::binary>>) do -    "audio/mpeg" -  end - -  defp check_mime_type(<<255, 251, _, 68, 0, 0, 0, 0, _::binary>>) do -    "audio/mpeg" -  end - -  defp check_mime_type( -         <<0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, _::size(160), 0x80, 0x74, 0x68, 0x65, -           0x6F, 0x72, 0x61, _::binary>> -       ) do -    "video/ogg" -  end - -  defp check_mime_type(<<0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, _::binary>>) do -    "audio/ogg" -  end - -  defp check_mime_type(<<"RIFF", _::binary-size(4), "WAVE", _::binary>>) do -    "audio/wav" -  end - -  defp check_mime_type(<<"RIFF", _::binary-size(4), "WEBP", _::binary>>) do -    "image/webp" -  end - -  defp check_mime_type(<<"RIFF", _::binary-size(4), "AVI.", _::binary>>) do -    "video/avi" -  end - -  defp check_mime_type(_) do -    @default -  end -end diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 015c87593..db2cc1dae 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -66,6 +66,7 @@ defmodule Pleroma.Upload do    end    @spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()} +  @doc "Store a file. If using a `Plug.Upload{}` as the source, be sure to use `Majic.Plug` to ensure its content_type and filename is correct."    def store(upload, opts \\ []) do      opts = get_opts(opts) @@ -139,14 +140,13 @@ defmodule Pleroma.Upload do    end    defp prepare_upload(%Plug.Upload{} = file, opts) do -    with :ok <- check_file_size(file.path, opts.size_limit), -         {:ok, content_type, name} <- Pleroma.MIME.file_mime_type(file.path, file.filename) do +    with :ok <- check_file_size(file.path, opts.size_limit) do        {:ok,         %__MODULE__{           id: UUID.generate(), -         name: name, +         name: file.filename,           tempfile: file.path, -         content_type: content_type +         content_type: file.content_type         }}      end    end @@ -154,16 +154,17 @@ defmodule Pleroma.Upload do    defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do      parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data)      data = Base.decode64!(parsed["data"], ignore: :whitespace) -    hash = String.downcase(Base.encode16(:crypto.hash(:sha256, data))) +    hash = Base.encode16(:crypto.hash(:sha256, data), lower: true)      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, %{mime_type: content_type}} <- +           Majic.perform({:bytes, data}, pool: Pleroma.MajicPool), +         [ext | _] <- MIME.extensions(content_type) do        {:ok,         %__MODULE__{           id: UUID.generate(), -         name: name, +         name: hash <> "." <> ext,           tempfile: tmp_path,           content_type: content_type         }} @@ -172,7 +173,7 @@ defmodule Pleroma.Upload do    # For Mix.Tasks.MigrateLocalUploads    defp prepare_upload(%__MODULE__{tempfile: path} = upload, _opts) do -    with {:ok, content_type} <- Pleroma.MIME.file_mime_type(path) do +    with {:ok, %{mime_type: content_type}} <- Majic.perform(path, pool: Pleroma.MajicPool) do        {:ok, %__MODULE__{upload | content_type: content_type}}      end    end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 6bf7421bb..570bcc7e7 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -45,6 +45,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      when action in [:read_inbox, :update_outbox, :whoami, :upload_media]    ) +  plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:upload_media]) +    plug(      Pleroma.Web.Plugs.Cache,      [query_params: false, tracking_fun: &__MODULE__.track_object_fetch/2] diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex index 9586b14bc..161193134 100644 --- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do    alias Pleroma.Web.Plugs.OAuthScopesPlug    action_fallback(Pleroma.Web.MastodonAPI.FallbackController) +  plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:create, :create2])    plug(Pleroma.Web.ApiSpec.CastAndValidate)    plug(:put_view, Pleroma.Web.MastodonAPI.StatusView) diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index 61f4a9bd9..30cf83567 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -18,6 +18,11 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do    require Pleroma.Constants    plug( +    Majic.Plug, +    [pool: Pleroma.MajicPool] when action in [:update_avatar, :update_background, :update_banner] +  ) + +  plug(      OpenApiSpex.Plug.PutApiSpec,      [module: Pleroma.Web.ApiSpec] when action == :confirmation_resend    ) diff --git a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex index 0f6f0b9db..15210f1e6 100644 --- a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.Plugs.OAuthScopesPlug +  plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:update])    plug(Pleroma.Web.ApiSpec.CastAndValidate)    plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :show)    plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action != :show) @@ -22,14 +23,15 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do    @doc "PUT /api/v1/pleroma/mascot"    def update(%{assigns: %{user: user}, body_params: %{file: file}} = conn, _) do -    with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), -         # Reject if not an image -         %{type: "image"} = attachment <- render_attachment(object) do +    with {:content_type, "image" <> _} <- {:content_type, file.content_type}, +         {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)) do +      attachment = render_attachment(object)        {:ok, _user} = User.mascot_update(user, attachment)        json(conn, attachment)      else -      %{type: _} -> render_error(conn, :unsupported_media_type, "mascots can only be images") +      {:content_type, _} -> +        render_error(conn, :unsupported_media_type, "mascots can only be images")      end    end  | 
