Merge branch 'deprecate-public_endpoint' into 'develop'
[akkoma] / lib / pleroma / upload.ex
index 015c875938967e3fed944f7eb21b46a85274cb96..6547113514b15fe3d74770f2fde3869930265223 100644 (file)
@@ -1,5 +1,5 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Upload do
@@ -31,6 +31,7 @@ defmodule Pleroma.Upload do
 
   """
   alias Ecto.UUID
+  alias Pleroma.Config
   require Logger
 
   @type source ::
@@ -66,6 +67,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)
 
@@ -129,24 +131,18 @@ defmodule Pleroma.Upload do
       uploader: Keyword.get(opts, :uploader, Pleroma.Config.get([__MODULE__, :uploader])),
       filters: Keyword.get(opts, :filters, Pleroma.Config.get([__MODULE__, :filters])),
       description: Keyword.get(opts, :description),
-      base_url:
-        Keyword.get(
-          opts,
-          :base_url,
-          Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url())
-        )
+      base_url: base_url()
     }
   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 +150,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 +169,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
@@ -215,16 +212,46 @@ defmodule Pleroma.Upload do
           ""
         end
 
-    prefix =
-      if is_nil(Pleroma.Config.get([__MODULE__, :base_url])) do
-        "media"
-      else
-        ""
-      end
-
-    [base_url, prefix, path]
+    [base_url, path]
     |> Path.join()
   end
 
   defp url_from_spec(_upload, _base_url, {:url, url}), do: url
+
+  def base_url do
+    uploader = Config.get([Pleroma.Upload, :uploader])
+    upload_base_url = Config.get([Pleroma.Upload, :base_url])
+    public_endpoint = Config.get([uploader, :public_endpoint])
+
+    case uploader do
+      Pleroma.Uploaders.Local ->
+        upload_base_url || Pleroma.Web.base_url() <> "/media/"
+
+      Pleroma.Uploaders.S3 ->
+        bucket = Config.get([Pleroma.Uploaders.S3, :bucket])
+        truncated_namespace = Config.get([Pleroma.Uploaders.S3, :truncated_namespace])
+        namespace = Config.get([Pleroma.Uploaders.S3, :bucket_namespace])
+
+        bucket_with_namespace =
+          cond do
+            !is_nil(truncated_namespace) ->
+              truncated_namespace
+
+            !is_nil(namespace) ->
+              namespace <> ":" <> bucket
+
+            true ->
+              bucket
+          end
+
+        if public_endpoint do
+          Path.join([public_endpoint, bucket_with_namespace])
+        else
+          Path.join([upload_base_url, bucket_with_namespace])
+        end
+
+      _ ->
+        public_endpoint || upload_base_url || Pleroma.Web.base_url() <> "/media/"
+    end
+  end
 end