Uploading to S3 from a remote URL returns a SignatureDoesNotMatch error
Opened this issue · 0 comments
MarbilleJuntado commented
In arc_ecto
, why do I get a SignatureDoesNotMatch
error when uploading a file from an external URL to my S3 bucket (e.g. File.upload_file(%{"attachment" => "http://sample.com/file.pdf"})
? I already configured my File model's changeset to allow paths when casting attachments.
def changeset(struct, params \\ %{}) do
struct
|> cast(params, @required_attrs ++ @optional_attrs)
|> cast_attachments(params, [:attachment], allow_paths: true)
|> validate_required(@required_attrs)
end
If attachment
is set as a Plug.Upload
, it works:
File.upload_file(%{
"attachment" => %Plug.Upload{
content_type: "application/pdf",
filename: "sample.pdf",
path: "/tmp/plug-1565/multipart-1565172398-694450657366843-1"
}
})
but not if it's a URL: File.upload_file(%{"attachment" => "http://sample.com/file.pdf"})
.
Here's how I set up my uploader:
defmodule MyApp.Uploaders.Attachment do
use Arc.Definition
use Arc.Ecto.Definition
alias Phoenix.Naming
@acl :private
# Whitelist file extensions:
def validate({file, _}) do
ext =
file
|> get_file_name
|> Path.extname()
|> String.downcase()
Enum.member?(~w(.jpg .jpeg .gif .png .pdf .docx .doc .odt), ext)
end
# Override the storage directory:
def storage_dir(_version, {_file, scope}) do
base_path = "uploads/attachments/#{scope_dir(scope)}/#{scope.id}"
if __storage() == Arc.Storage.Local do
"priv/static/" <> base_path
else
base_path
end
end
# Specify custom headers for s3 objects
# Available options are [:cache_control, :content_disposition,
# :content_encoding, :content_length, :content_type,
# :expect, :expires, :storage_class, :website_redirect_location]
#
def s3_object_headers(_version, {file, _scope}) do
filename = get_file_name(file)
[content_type: MIME.from_path(filename)]
end
defp scope_dir(scope) do
scope.__struct__
|> Atom.to_string()
|> String.split(".")
|> List.last()
|> Naming.underscore()
end
defp get_file_name(%{file_name: file_name}), do: file_name
defp get_file_name(%{filename: filename}), do: filename
end