diff --git a/core/priv/gettext/en/LC_MESSAGES/eyra-storage.po b/core/priv/gettext/en/LC_MESSAGES/eyra-storage.po index a506ecdec..47b10a265 100644 --- a/core/priv/gettext/en/LC_MESSAGES/eyra-storage.po +++ b/core/priv/gettext/en/LC_MESSAGES/eyra-storage.po @@ -75,6 +75,10 @@ msgstr "WebDAV Url" msgid "surfresearchdrive.folder.label" msgstr "Folder name" +#, elixir-autogen, elixir-format +msgid "surfresearchdrive.passphrase.label" +msgstr "Passphrase for encryption" + #, elixir-autogen, elixir-format msgid "aws.annotation" msgstr "
Use Amazon S3 storage. More information: https://aws.amazon.com/s3
" diff --git a/core/priv/gettext/eyra-storage.pot b/core/priv/gettext/eyra-storage.pot index afa3f495b..2151bb1ac 100644 --- a/core/priv/gettext/eyra-storage.pot +++ b/core/priv/gettext/eyra-storage.pot @@ -75,6 +75,10 @@ msgstr "" msgid "surfresearchdrive.folder.label" msgstr "" +#, elixir-autogen, elixir-format +msgid "surfresearchdrive.passphrase.label" +msgstr "" + #, elixir-autogen, elixir-format msgid "aws.annotation" msgstr "" diff --git a/core/priv/repo/migrations/20231025125051_add_storage.exs b/core/priv/repo/migrations/20231025125051_add_storage.exs index e2a6f573f..06ba19dc9 100644 --- a/core/priv/repo/migrations/20231025125051_add_storage.exs +++ b/core/priv/repo/migrations/20231025125051_add_storage.exs @@ -38,6 +38,7 @@ defmodule Core.Repo.Migrations.AddStorage do add(:password, :string) add(:url, :string) add(:folder, :string) + add(:passphrase, :string) timestamps() end diff --git a/core/systems/storage/surfresearchdrive/backend.ex b/core/systems/storage/surfresearchdrive/backend.ex index 407a313cb..eb4a56e7a 100644 --- a/core/systems/storage/surfresearchdrive/backend.ex +++ b/core/systems/storage/surfresearchdrive/backend.ex @@ -1,7 +1,7 @@ defmodule Systems.Storage.SurfResearchDrive.Backend do @behaviour Systems.Storage.Backend - alias Systems.Storage.SurfResearchDrive + alias Systems.Storage.SurfResearchDrive.Encryption require Logger @@ -10,7 +10,8 @@ defmodule Systems.Storage.SurfResearchDrive.Backend do "user" => username, "password" => password, "url" => url, - "folder" => folder + "folder" => folder, + "passphrase" => passphrase, } = _endpoint, data, meta_data @@ -24,6 +25,13 @@ defmodule Systems.Storage.SurfResearchDrive.Backend do {"Authorization", "Basic #{credentials}"} ] + + data = if passphrase != nil do + Encryption.encrypt(data, passphrase) + else + data + end + case HTTPoison.put(file_url, data, headers) do {:ok, %{status_code: 201}} -> :ok @@ -32,7 +40,7 @@ defmodule Systems.Storage.SurfResearchDrive.Backend do {:error, "status_code=#{status_code},message=#{body}"} {:error, error} -> - Logger.error("[SurfResearchDrive.Backend] #{error}") + IO.inspect(error) {:error, error} end end diff --git a/core/systems/storage/surfresearchdrive/encryption.ex b/core/systems/storage/surfresearchdrive/encryption.ex new file mode 100644 index 000000000..f2cda456c --- /dev/null +++ b/core/systems/storage/surfresearchdrive/encryption.ex @@ -0,0 +1,42 @@ +defmodule Systems.Storage.SurfResearchDrive.Encryption do + @moduledoc """ + Documentation for `Systems.Storage.SurfResearchDrive.Encryption`. + """ + + @doc """ + Encrypt file with AES-256-CBC + + The hashed passphrase is the encryption key + The hash function is there to guarantee the key consists of 256 bits + The hasing function does not offer protection. + If you know the hash or the passphrase you can decrypt the data + + Decryption can be done with: + openssl enc -d -aes-256-cbc -in <(tail -c +17 file.enc) \ + -out file.txt \ + -K \ + -iv + """ + def encrypt(content, passphrase) do + + # generate key and iv + key = :crypto.hash(:sha256, passphrase) + iv = :crypto.strong_rand_bytes(16) + + padded_content = pad(content, 16) + + # Encrypt content + cipher_text = :crypto.crypto_one_time(:aes_256_cbc, key, iv, padded_content, true) + + # Prepend IV and write the result + iv <> cipher_text + end + + @doc """ + Applies PKCS7 padding to the given binary. + """ + def pad(data, block_size) do + padding_size = block_size - rem(byte_size(data), block_size) + data <> :binary.copy(<>, padding_size) + end +end diff --git a/core/systems/storage/surfresearchdrive/endpoint_form.ex b/core/systems/storage/surfresearchdrive/endpoint_form.ex index 0aaf8a02d..d3b960935 100644 --- a/core/systems/storage/surfresearchdrive/endpoint_form.ex +++ b/core/systems/storage/surfresearchdrive/endpoint_form.ex @@ -13,11 +13,9 @@ defmodule Systems.Storage.SurfResearchDrive.EndpointForm do <.password_input form={form} field={:password} label_text={dgettext("eyra-storage", "surfresearchdrive.password.label")} debounce="0" reserve_error_space={false} /> <.text_input form={form} field={:url} label_text={dgettext("eyra-storage", "surfresearchdrive.url.label")} placeholder="https://{url}/remote.php/webdav/>" debounce="0" reserve_error_space={false} /> <.text_input form={form} field={:folder} label_text={dgettext("eyra-storage", "surfresearchdrive.folder.label")} debounce="0" reserve_error_space={false} /> + <.text_input form={form} field={:passphrase} label_text={dgettext("eyra-storage", "surfresearchdrive.passphrase.label")} placeholder="Leave blank for no encryption" debounce="0" reserve_error_space={false} />
- <%= if @show_status do %> - <.account_status connected?={@connected?}/> - <% end %>
diff --git a/core/systems/storage/surfresearchdrive/endpoint_model.ex b/core/systems/storage/surfresearchdrive/endpoint_model.ex index ae5d68a4d..05fdd8c6d 100644 --- a/core/systems/storage/surfresearchdrive/endpoint_model.ex +++ b/core/systems/storage/surfresearchdrive/endpoint_model.ex @@ -5,16 +5,17 @@ defmodule Systems.Storage.SurfResearchDrive.EndpointModel do import Ecto.Changeset alias Systems.Storage.SurfResearchDrive - @fields ~w(user password url folder)a + @fields ~w(user password url folder passphrase)a @required_fields @fields @derive {Jason.Encoder, only: @fields} - @derive {Inspect, except: [:user, :password]} + @derive {Inspect, except: [:user, :password, :passphrase]} schema "storage_endpoints_surfresearchdrive" do field(:user, :string) field(:password, :string) field(:url, :string) field(:folder, :string) + field(:passphrase, :string) timestamps() end