fix: Correct path for social media preview images
This commit is contained in:
parent
6a1eac6b1e
commit
2e6ecd2a89
9 changed files with 78 additions and 25 deletions
|
@ -5,6 +5,7 @@ defmodule Legendary.ContentWeb.Uploaders.SocialMediaPreview do
|
|||
use Waffle.Definition
|
||||
|
||||
@versions [:original]
|
||||
@acl :public_read
|
||||
|
||||
# Override the persisted filenames:
|
||||
def filename(version, _) do
|
||||
|
|
|
@ -17,6 +17,8 @@ defmodule Legendary.ObjectStorage.Object do
|
|||
|
||||
@doc false
|
||||
def changeset(object, attrs \\ %{}) do
|
||||
attrs = format_acl(attrs)
|
||||
|
||||
object
|
||||
|> cast(attrs, [:path, :body, :acl])
|
||||
|> validate_required([:path, :acl])
|
||||
|
@ -24,6 +26,11 @@ defmodule Legendary.ObjectStorage.Object do
|
|||
|> validate_inclusion(:acl, @acl_values, message: "is not supported. Valid values are #{@acl_values |> Enum.map(&Atom.to_string/1) |> Enum.join(",")}.")
|
||||
end
|
||||
|
||||
defp format_acl(%{acl: acl} = attrs) do
|
||||
%{attrs | acl: Recase.to_snake(acl)}
|
||||
end
|
||||
defp format_acl(attrs), do: attrs
|
||||
|
||||
defp validate_body_or_upload(changeset, attrs) do
|
||||
case attrs do
|
||||
%{uploads: "1"} ->
|
||||
|
|
|
@ -33,12 +33,17 @@ defmodule Legendary.ObjectStorageWeb.CheckSignatures do
|
|||
end
|
||||
|
||||
def actual_signature_for_conn(conn) do
|
||||
%{"Signature" => actual_signature} =
|
||||
parsed_header =
|
||||
conn
|
||||
|> get_first_request_header("authorization")
|
||||
|> signature_generator().parse_authorization_header()
|
||||
|
||||
{:ok, actual_signature}
|
||||
case parsed_header do
|
||||
%{"Signature" => actual_signature} ->
|
||||
{:ok, actual_signature}
|
||||
_ ->
|
||||
{:error, :no_signature}
|
||||
end
|
||||
end
|
||||
|
||||
defp signature_generator() do
|
||||
|
|
|
@ -26,18 +26,26 @@ defmodule Legendary.ObjectStorageWeb.CheckSignatures.SignatureGenerator do
|
|||
config = ExAws.Config.new(:s3)
|
||||
url = url_to_sign(conn, config)
|
||||
sanitized_query_string = Regex.replace(@signature_in_query_pattern, conn.query_string, "")
|
||||
headers = filtered_headers(conn)
|
||||
|
||||
{:ok, signature(
|
||||
conn.method |> String.downcase() |> String.to_atom(),
|
||||
url,
|
||||
sanitized_query_string,
|
||||
filtered_headers(conn),
|
||||
body_for_request(conn),
|
||||
conn |> request_datetime() |> amz_date_parse(),
|
||||
config
|
||||
)}
|
||||
case headers do
|
||||
:error ->
|
||||
:error
|
||||
|
||||
_ ->
|
||||
{:ok, signature(
|
||||
conn.method |> String.downcase() |> String.to_atom(),
|
||||
url,
|
||||
sanitized_query_string,
|
||||
headers,
|
||||
body_for_request(conn),
|
||||
conn |> request_datetime() |> amz_date_parse(),
|
||||
config
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
def parse_authorization_header(nil), do: :error
|
||||
def parse_authorization_header(header) do
|
||||
["AWS4-HMAC-SHA256", params] = String.split(header, " ")
|
||||
|
||||
|
@ -62,19 +70,27 @@ defmodule Legendary.ObjectStorageWeb.CheckSignatures.SignatureGenerator do
|
|||
defp request_datetime(conn), do: get_first_request_header(conn, "x-amz-date")
|
||||
|
||||
defp filtered_headers(conn) do
|
||||
signed_header_keys =
|
||||
case conn.params do
|
||||
%{"X-Amz-SignedHeaders" => signed_header_string} ->
|
||||
signed_header_string
|
||||
_ ->
|
||||
conn
|
||||
|> get_first_request_header("authorization")
|
||||
|> parse_authorization_header()
|
||||
|> Map.get("SignedHeaders")
|
||||
end
|
||||
|> String.split(";")
|
||||
case filtered_header_names(conn) do
|
||||
:error -> :error
|
||||
signed_header_keys ->
|
||||
Enum.filter(conn.req_headers, fn {k, _v} -> k in signed_header_keys end)
|
||||
end
|
||||
end
|
||||
|
||||
Enum.filter(conn.req_headers, fn {k, _v} -> k in signed_header_keys end)
|
||||
defp filtered_header_names(%{params: %{"X-Amz-SignedHeaders" => signed_header_string}}) do
|
||||
String.split(signed_header_string, ";")
|
||||
end
|
||||
defp filtered_header_names(conn) do
|
||||
header = get_first_request_header(conn, "authorization")
|
||||
|
||||
if header do
|
||||
header
|
||||
|> parse_authorization_header()
|
||||
|> Map.get("SignedHeaders")
|
||||
|> String.split(";")
|
||||
else
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
# Presigned URL, so do not include body (unknown when presigning) to sig calc
|
||||
|
|
|
@ -59,6 +59,7 @@ defmodule Legendary.ObjectStorage.MixProject do
|
|||
{:phoenix_pubsub, "~> 2.0"},
|
||||
{:plug_cowboy, "~> 2.5"},
|
||||
{:postgrex, ">= 0.0.0"},
|
||||
{:recase, "~> 0.7.0"},
|
||||
{:sweet_xml, "~> 0.7.1"},
|
||||
{:telemetry_metrics, "~> 0.6"},
|
||||
{:telemetry_poller, "~> 1.0"}
|
||||
|
|
|
@ -2,6 +2,9 @@ defmodule ObjectStorageWeb.UploadControllerTest do
|
|||
use Legendary.ObjectStorageWeb.ConnCase
|
||||
|
||||
alias Legendary.ObjectStorage.{Object, Repo}
|
||||
alias Legendary.ObjectStorageWeb.CheckSignatures.{MockSignatureGenerator, SignatureGenerator}
|
||||
|
||||
import Mox
|
||||
|
||||
def put_request(conn, path, acl, body, params \\ %{}, content_type \\ "text/plain") do
|
||||
conn
|
||||
|
@ -25,6 +28,25 @@ defmodule ObjectStorageWeb.UploadControllerTest do
|
|||
assert response_content_type(conn, :xml)
|
||||
end
|
||||
|
||||
test "returns 404 if the object is private and there are no sig headers", %{conn: conn} do
|
||||
verify_on_exit!()
|
||||
|
||||
MockSignatureGenerator
|
||||
|> expect(:correct_signature_for_conn, fn _conn -> {:ok, "good-sig"} end)
|
||||
|> expect(:parse_authorization_header,
|
||||
fn header ->
|
||||
SignatureGenerator.parse_authorization_header(header)
|
||||
end
|
||||
)
|
||||
|
||||
Repo.insert!(%Object{path: "secret.txt", acl: :private, body: "Ssh!"})
|
||||
|
||||
conn = get(conn, Routes.upload_path(conn, :show, ["secret.txt"]))
|
||||
|
||||
assert response(conn, 404)
|
||||
assert response_content_type(conn, :xml)
|
||||
end
|
||||
|
||||
test "returns the object if the object is private but the sig check passes", %{conn: conn} do
|
||||
expect_signature_checks_and_pass()
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ config :libcluster,
|
|||
config :waffle,
|
||||
storage: Waffle.Storage.S3,
|
||||
bucket: "uploads",
|
||||
asset_host: "http://localhost:4000"
|
||||
asset_host: "http://localhost:4000/uploads"
|
||||
|
||||
# ## SSL Support
|
||||
#
|
||||
|
|
|
@ -105,7 +105,7 @@ config :libcluster,
|
|||
config :waffle,
|
||||
storage: Waffle.Storage.S3,
|
||||
bucket: "uploads",
|
||||
asset_host: "https://#{System.get_env("HOSTNAME")}"
|
||||
asset_host: "https://#{System.get_env("HOSTNAME")}/uploads"
|
||||
|
||||
config :object_storage,
|
||||
bucket_name: "uploads"
|
||||
|
|
1
mix.lock
1
mix.lock
|
@ -80,6 +80,7 @@
|
|||
"pow": {:hex, :pow, "1.0.25", "70bd2a6c08ac2edcea4a059696ea747af9e8d469c39c247634c9ee7095845f41", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.3.0 and < 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and < 4.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "141d39099024a83b84137dc7b26456792f4c60e5376ad1d2b835b9597767bc00"},
|
||||
"quantum": {:hex, :quantum, "2.4.0", "f2ad4b20988f848455d35ed0e884ba0c7629a27ee86cbec6a6e0fc214b6e69cf", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: true]}], "hexpm", "a125a9e65a5af740a1198f3b05c1a736fce3942f5e0dc2901e0f9be5745bea99"},
|
||||
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
|
||||
"recase": {:hex, :recase, "0.7.0", "3f2f719f0886c7a3b7fe469058ec539cb7bbe0023604ae3bce920e186305e5ae", [:mix], [], "hexpm", "36f5756a9f552f4a94b54a695870e32f4e72d5fad9c25e61bc4a3151c08a4e0c"},
|
||||
"sitemap": {:hex, :sitemap, "1.1.0", "23a019cccef7c17090d0b493354ee47a94549db64fd1cf39bda7eb41c567729c", [:mix], [{:xml_builder, ">= 0.0.0", [hex: :xml_builder, repo: "hexpm", optional: false]}], "hexpm", "d21f2c3ac65567fbdbe231f9faaf802a48405aa487d24052964d3d818a3d8c22"},
|
||||
"slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
|
||||
|
|
Loading…
Reference in a new issue