Skip to content

Commit

Permalink
Merge pull request #15 from bettyblocks/feat/implement-external-host-…
Browse files Browse the repository at this point in the history
…config-DT-4108

Feat/implement external host config dt 4108
  • Loading branch information
nulian authored Aug 12, 2024
2 parents dc79044 + 36d19d0 commit 8d9b327
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 23 deletions.
14 changes: 9 additions & 5 deletions lib/api/s3/base.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ defmodule FileStorageApi.API.S3.Base do
secret_access_key: Access.get(s3_config, :secret_key),
s3_auth_version: Access.get(s3_config, :s3_auth_version, 4),
host: Access.get(s3_config, :host),
external_host: Access.get(s3_config, :external_host),
scheme: Access.get(s3_config, :scheme),
port: Access.get(s3_config, :port),
http_opts: http_opts()
Expand Down Expand Up @@ -70,11 +71,14 @@ defmodule FileStorageApi.API.S3.Base do
storage_api = Application.get_env(:file_storage_api, :storage_api, [])

case Keyword.get(storage_api, :custom_ca_cert) do
cert when is_binary(cert) and byte_size(cert) > 0 -> [
{:ssl, [cacertfile: cert]},
{:ssl_options, [cacertfile: cert, verify: :verify_peer]}
]
_ -> []
cert when is_binary(cert) and byte_size(cert) > 0 ->
[
{:ssl, [cacertfile: cert]},
{:ssl_options, [cacertfile: cert, verify: :verify_peer]}
]

_ ->
[]
end
end
end
45 changes: 28 additions & 17 deletions lib/api/s3/file.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,35 +35,46 @@ defmodule FileStorageApi.API.S3.File do
def public_url(container_name, "/" <> file_path, opts), do: public_url(container_name, file_path, opts)

def public_url(container_name, file_path, opts) do
is_public = Keyword.get(opts, :public, false)
public? = Keyword.get(opts, :public, false)
connection = Keyword.get(opts, :connection)
start_time = Keyword.get(opts, :start_time)
expire_time = Keyword.get(opts, :expire_time)

expires_in = Timex.Comparable.diff(expire_time, start_time, :seconds)
storage_config = config(connection)

s3_signed =
S3.presigned_url(Config.new(:s3, config(connection)), :get, container_name, file_path, expires_in: expires_in)
S3.presigned_url(Config.new(:s3, storage_config), :get, container_name, file_path, expires_in: expires_in)

case s3_signed do
{:ok, url} ->
if is_public do
public_url =
url
|> URI.parse()
|> Map.put(:query, nil)
|> URI.to_string()

{:ok, public_url}
else
{:ok, url}
end

error ->
error
{:ok, url} -> {:ok, transform_url(url, public?, storage_config)}
error -> error
end
end

@spec transform_url(binary, boolean, Keyword.t()) :: binary
defp transform_url(signed_url, public?, storage_config) do
signed_url
|> URI.parse()
|> replace_host(storage_config[:external_host])
|> remove_query_params(public?)
|> URI.to_string()
end

@spec replace_host(URI.t(), binary | nil) :: URI.t()
defp replace_host(parsed_url, nil), do: parsed_url

defp replace_host(parsed_url, external_host) when is_binary(external_host) do
Map.put(parsed_url, :host, external_host)
end

@spec remove_query_params(URI.t(), boolean) :: URI.t()
defp remove_query_params(parsed_url, true) do
Map.put(parsed_url, :query, nil)
end

defp remove_query_params(parsed_url, _), do: parsed_url

@impl true
def last_modified(%FileStorageApi.File{properties: %{last_modified: timestamp}}) do
Timex.parse(timestamp, "{ISO:Extended}")
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule FileStorageApi.MixProject do
def project do
[
app: :file_storage_api,
version: "2.1.4",
version: "2.2.0",
elixir: "~> 1.10",
elixirc_paths: elixirc_paths(Mix.env()),
elixirc_options: [warnings_as_errors: Mix.env() != :test],
Expand Down
37 changes: 37 additions & 0 deletions test/api/s3/file_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ defmodule FileStorageApi.API.S3.FileTest do
uri = URI.parse(url)

assert "/block-store-container/test.png" == uri.path
assert "test.docker" == uri.host
assert uri.query =~ "AWS4-HMAC-SHA256"
end

test "able to create a public url for files also works with / at start" do
Expand All @@ -136,6 +138,7 @@ defmodule FileStorageApi.API.S3.FileTest do
uri = URI.parse(url)

assert "/block-store-container/test.png" == uri.path
assert "test.docker" == uri.host
end

test "timestamps should be correctly set in url" do
Expand Down Expand Up @@ -188,5 +191,39 @@ defmodule FileStorageApi.API.S3.FileTest do
assert {:error, %{}} =
File.upload("block-store-container", @connection, file_path, nil, content_type: "image/png")
end

test "signing with external host will replace the host" do
{:ok, url} =
File.public_url(
"block-store-container",
"test.png",
start_time: Timex.now(),
expire_time: Timex.add(Timex.now(), Timex.Duration.from_days(1)),
connection: put_in(@connection, [:config, :external_host], "example.com")
)

uri = URI.parse(url)

assert "/block-store-container/test.png" == uri.path
assert "example.com" == uri.host
end

test "signing with public removes the signature" do
{:ok, url} =
File.public_url(
"block-store-container",
"test.png",
start_time: Timex.now(),
expire_time: Timex.add(Timex.now(), Timex.Duration.from_days(1)),
connection: @connection,
public: true
)

uri = URI.parse(url)

assert "/block-store-container/test.png" == uri.path
assert "test.docker" == uri.host
assert is_nil(uri.query)
end
end
end

0 comments on commit 8d9b327

Please sign in to comment.