Files
2025-11-29 12:34:28 +01:00

133 lines
3.1 KiB
Elixir

defmodule WandererApp.Vault do
use Cloak.Vault, otp_app: :wanderer_app
@impl GenServer
def init(config) do
cipher_key = decode_env!("CLOAK_KEY")
fallback_cipher_key = decode_env!("FALLBACK_CLOAK_KEY")
config =
Keyword.put(config, :ciphers,
default: {
Cloak.Ciphers.AES.GCM,
tag: "AES.GCM.V1", key: cipher_key, iv_length: 12
},
fallback: {
Cloak.Ciphers.AES.GCM,
tag: "AES.GCM.V1", key: fallback_cipher_key, iv_length: 12
}
)
{:ok, config}
end
@impl Cloak.Vault
def encrypt(plaintext) do
with {:ok, config} <- Cloak.Vault.read_config(@table_name) do
Cloak.Vault.encrypt(config, plaintext)
end
end
@impl Cloak.Vault
def encrypt!(plaintext) do
case Cloak.Vault.read_config(@table_name) do
{:ok, config} ->
Cloak.Vault.encrypt!(config, plaintext)
{:error, error} ->
raise error
end
end
@impl Cloak.Vault
def encrypt(plaintext, label) do
with {:ok, config} <- Cloak.Vault.read_config(@table_name) do
Cloak.Vault.encrypt(config, plaintext, label)
end
end
@impl Cloak.Vault
def encrypt!(plaintext, label) do
case Cloak.Vault.read_config(@table_name) do
{:ok, config} ->
Cloak.Vault.encrypt!(config, plaintext, label)
{:error, error} ->
raise error
end
end
@impl Cloak.Vault
def decrypt(ciphertext) do
with {:ok, config} <- Cloak.Vault.read_config(@table_name) do
decrypt(config, ciphertext)
end
end
@impl Cloak.Vault
def decrypt!(ciphertext) do
case Cloak.Vault.read_config(@table_name) do
{:ok, config} ->
decrypt!(config, ciphertext)
{:error, error} ->
raise error
end
end
defp decode_env!(var, fallback_key \\ "OtPJXGfKNyOMWI7TdpcWgOlyNtD9AGSfoAdvEuTQIno=") do
var
|> System.get_env(fallback_key)
|> Base.decode64!()
end
@doc false
def decrypt(config, ciphertext) do
case find_module_to_decrypt(config, ciphertext) do
nil ->
{:error, Cloak.MissingCipher.exception(vault: config[:vault], ciphertext: ciphertext)}
{_label, {module, opts}} ->
case module.decrypt(ciphertext, opts) do
{:ok, :error} ->
case find_fallback_module_to_decrypt(config, ciphertext) do
nil ->
{:ok, :error}
{_label, {module, opts}} ->
module.decrypt(ciphertext, opts)
end
{:ok, plaintext} ->
{:ok, plaintext}
error ->
error
end
end
end
@doc false
def decrypt!(config, ciphertext) do
case decrypt(config, ciphertext) do
{:ok, plaintext} ->
plaintext
{:error, error} ->
raise error
end
end
defp find_module_to_decrypt(config, ciphertext) do
Enum.find(config[:ciphers], fn {_label, {module, opts}} ->
module.can_decrypt?(ciphertext, opts)
end)
end
defp find_fallback_module_to_decrypt(config, _ciphertext) do
Enum.find(config[:ciphers], fn {label, _} ->
label == :fallback
end)
end
end