fix: Correct path for social media preview images

This commit is contained in:
Robert Prehn 2021-10-21 17:03:49 -05:00
parent 6a1eac6b1e
commit 2e6ecd2a89
9 changed files with 78 additions and 25 deletions

View file

@ -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

View file

@ -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"} ->

View file

@ -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

View file

@ -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

View file

@ -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"}

View file

@ -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()

View file

@ -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
#

View file

@ -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"

View file

@ -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"},