Add mix task for decrypting uploads

This commit is contained in:
Shadowfacts 2021-09-06 15:06:51 -04:00
parent a1dad5d71d
commit 050e6e44a5
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
2 changed files with 44 additions and 2 deletions

View File

@ -0,0 +1,23 @@
defmodule Mix.Tasks.Wiki.Upload do
use Mix.Task
alias Wiki.{Repo, Accounts, Accounts.User, Content.Upload}
@shortdoc "Decrypts an upload into the given file"
def run(["decrypt", id, output_file]) do
email = IO.gets("Email: ") |> String.trim()
password = IO.gets("Password: ") |> String.trim()
Mix.Task.run("app.start")
user = Repo.get_by!(User, email: email)
upload = Repo.get!(Upload, String.to_integer(id)) |> Repo.preload(:page)
if upload.page.user_id != user.id do
raise "upload owner does not match provided user"
else
key = Accounts.generate_content_encryption_key(user, %{"password" => password})
key = Base.decode16!(key, case: :lower)
Upload.decrypt_to_file(upload, key, output_file)
end
end
end

View File

@ -80,7 +80,7 @@ defmodule Wiki.Content.Upload do
end
@spec upload_dir() :: String.t()
defp upload_dir() do
def upload_dir() do
dir = Application.get_env(:wiki, :upload_dir)
if is_nil(dir) do
@ -98,6 +98,25 @@ defmodule Wiki.Content.Upload do
:crypto.crypto_one_time(:aes_256_ctr, key, iv, encrypted_data, false)
end
@spec decrypt_to_file(t(), binary(), String.t()) :: File.t()
def decrypt_to_file(upload, key, path) when is_binary(path) do
{:ok, output} = File.open(path, [:write, :binary])
:ok = decrypt_to_file(upload, key, output)
File.close(output)
end
@spec decrypt_to_file(t(), binary(), File.io_device()) :: File.t()
def decrypt_to_file(upload, key, output) do
decrypt_stream(upload, key)
|> Enum.each(fn data ->
IO.binwrite(output, data)
end)
:ok
end
@spec decrypt_stream(t(), binary()) :: Enumerable.t()
def decrypt_stream(%__MODULE__{relative_path: filename, encryption_iv: iv}, key) do
start_fun = fn ->
@ -125,7 +144,7 @@ defmodule Wiki.Content.Upload do
end
end
after_fun = fn {state, input_dev} ->
after_fun = fn {_state, input_dev} ->
File.close(input_dev)
end