Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uploading to S3 from a remote URL returns a SignatureDoesNotMatch error #118

Open
MarbilleJuntado opened this issue Aug 7, 2019 · 0 comments

Comments

@MarbilleJuntado
Copy link

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant