Send decrypted upload response as chunked

This commit is contained in:
Shadowfacts 2021-04-11 10:44:53 -04:00
parent 0d51f9de3d
commit fd8bf97459
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
2 changed files with 49 additions and 4 deletions

View File

@ -98,6 +98,40 @@ defmodule Wiki.Content.Upload do
:crypto.crypto_one_time(:aes_256_ctr, key, iv, encrypted_data, false)
end
@spec decrypt_stream(t(), binary()) :: Enumerable.t()
def decrypt_stream(%__MODULE__{relative_path: filename, encryption_iv: iv}, key) do
start_fun = fn ->
state = :crypto.crypto_init(:aes_256_ctr, key, iv, false)
path = Path.join(upload_dir(), filename)
{:ok, input} = File.open(path, [:read, :binary])
{state, input, false}
end
next_fun = fn {state, input_dev, halt} ->
if halt do
{:halt, {state, input_dev}}
else
# why 4k?
{halt, data} =
case IO.binread(input_dev, 4096) do
:eof ->
{true, :crypto.crypto_final(state)}
data ->
{false, :crypto.crypto_update(state, data)}
end
{[data], {state, input_dev, halt}}
end
end
after_fun = fn {state, input_dev} ->
File.close(input_dev)
end
Stream.resource(start_fun, next_fun, after_fun)
end
@spec delete_file(upload :: t()) :: :ok
def delete_file(%__MODULE__{relative_path: filename}) do
File.rm(Path.join(upload_dir(), filename))

View File

@ -141,11 +141,22 @@ defmodule WikiWeb.PageController do
key = get_session(conn, :content_encryption_key)
key = Base.decode16!(key, case: :lower)
data = Upload.decrypt_content(upload, key)
conn =
conn
|> put_resp_header("content-type", upload.content_type)
|> send_chunked(200)
conn
|> put_resp_header("content-type", upload.content_type)
|> send_resp(200, data)
upload
|> Upload.decrypt_stream(key)
|> Enum.reduce_while(conn, fn decrypted_chunk, conn ->
case chunk(conn, decrypted_chunk) do
{:ok, conn} ->
{:cont, conn}
{:error, :closed} ->
{:halt, {:halt, conn}}
end
end)
end
def delete_upload(conn, _params) do