diff --git a/lib/cloak_ecto/type.ex b/lib/cloak_ecto/type.ex index 739c5bc..ada2a36 100644 --- a/lib/cloak_ecto/type.ex +++ b/lib/cloak_ecto/type.ex @@ -39,7 +39,8 @@ defmodule Cloak.Ecto.Type do def dump(value) do with {:ok, value} <- cast(value), value <- before_encrypt(value), - {:ok, value} <- encrypt(value) do + {:ok, value} <- encrypt(value), + {:ok, value} <- after_encrypt(value) do {:ok, value} else _other -> @@ -73,7 +74,8 @@ defmodule Cloak.Ecto.Type do end def load(value) do - with {:ok, value} <- decrypt(value) do + with {:ok, value} <- before_decrypt(value), + {:ok, value} <- decrypt(value) do value = after_decrypt(value) if unquote(closure) do @@ -90,11 +92,18 @@ defmodule Cloak.Ecto.Type do @doc false def before_encrypt(value), do: to_string(value) + def after_encrypt(value), do: {:ok, value} + + @doc false + def before_decrypt(value), do: {:ok, value} + @doc false def after_decrypt(value), do: value - defoverridable after_decrypt: 1, + defoverridable before_decrypt: 1, + after_decrypt: 1, before_encrypt: 1, + after_encrypt: 1, cast: 1, dump: 1, embed_as: 1, diff --git a/lib/cloak_ecto/types/binary.ex b/lib/cloak_ecto/types/binary.ex index 077a90b..944a207 100644 --- a/lib/cloak_ecto/types/binary.ex +++ b/lib/cloak_ecto/types/binary.ex @@ -30,6 +30,20 @@ defmodule Cloak.Ecto.Binary do quote location: :keep do use Cloak.Ecto.Type, unquote(opts) + if unquote(opts[:embed]) do + def embed_as(_format) do + :dump + end + + def before_decrypt(value) do + Base.decode64(value, padding: false) + end + + def after_encrypt(value) do + {:ok, Base.encode64(value, padding: false)} + end + end + def cast(closure) when is_function(closure, 0) do cast(closure.()) end diff --git a/test/cloak_ecto/types/binary_test.exs b/test/cloak_ecto/types/binary_test.exs index 08a1243..55ea673 100644 --- a/test/cloak_ecto/types/binary_test.exs +++ b/test/cloak_ecto/types/binary_test.exs @@ -5,6 +5,10 @@ defmodule Cloak.Ecto.BinaryTest do use Cloak.Ecto.Binary, vault: Cloak.Ecto.TestVault end + defmodule EmbeddedField do + use Cloak.Ecto.Binary, vault: Cloak.Ecto.TestVault, embed: true + end + defmodule ClosureField do use Cloak.Ecto.Binary, vault: Cloak.Ecto.TestVault, closure: true end @@ -47,6 +51,11 @@ defmodule Cloak.Ecto.BinaryTest do assert ciphertext != "value" end + test "encrypts and base64 encodes embedded binaries" do + {:ok, ciphertext} = EmbeddedField.dump("value") + assert Base.decode64!(ciphertext, padding: false) != "value" + end + test "returns :error on other types" do for invalid <- @invalid_types do assert :error == Field.dump(invalid) @@ -60,6 +69,13 @@ defmodule Cloak.Ecto.BinaryTest do assert {:ok, "value"} = Field.load(ciphertext) end + test "decrypts an embedded ciphertext" do + {:ok, ciphertext} = EmbeddedField.dump("value") + assert {:ok, "value"} = EmbeddedField.load(ciphertext) + + assert {:ok, "value"} = ciphertext |> Base.decode64!(padding: false) |> Field.load() + end + test "closure option wraps decrypted value" do {:ok, ciphertext} = ClosureField.dump("value") assert {:ok, closure} = ClosureField.load(ciphertext)