### Database Table Creation for Encrypted Data Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Example SQL statement to create a 'users' table with binary fields for email and email_hash. The `:binary` type in Ecto is used for storing the encrypted and hashed data. ```sql create table(:users) do add :email, :binary add :email_hash, :binary # will be used for searching # ... timestamps() end ``` -------------------------------- ### Define Cloak.Vault with Static Key Configuration Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Define a Cloak.Vault module for your application. This example shows how to configure the vault with a static, Base64 decoded encryption key directly within the configuration. Ensure the key is decoded into its raw binary form. ```elixir defmodule MyApp.Vault do use Cloak.Vault, otp_app: :my_app end config :my_app, MyApp.Vault, ciphers: [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: Base.decode64!("your-key-here")} ] ``` -------------------------------- ### Add Vault to Supervision Tree Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Include your custom `MyApp.Vault` module in the application's supervision tree to ensure it is started and managed correctly. ```elixir children = [ MyApp.Vault ] ``` -------------------------------- ### Add Cloak.Ecto Dependency to mix.exs Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Add the :cloak_ecto dependency to your project's mix.exs file. This will also install the :cloak` package as a dependency. After adding, run `mix deps.get` to fetch the packages. ```elixir {:cloak_ecto, "~> 1.2.0"} ``` -------------------------------- ### Local Development Setup with Docker Source: https://github.com/danielberkompas/cloak_ecto/blob/master/README.md This set of shell commands outlines the process for setting up the Cloak.Ecto project for local development using Docker and docker-compose. It includes commands to run tests within the Docker environment, access a bash terminal with Mix, and generate documentation. ```sh $ cd cloak_ecto # Runs the bin/test script in the context of Docker $ docker-compose run code bin/test # To access a terminal with mix, use this command: $ docker-compose run code bash # Run any command of your choosing: root@234098234oij:/app# mix docs ``` -------------------------------- ### Install cloak_ecto Dependency Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/upgrading/0.9.x_to_1.0.x.md This snippet shows how to replace the 'cloak' dependency with 'cloak_ecto' in your project's mix.exs file to use version 1.0.0. ```elixir {:cloak_ecto, "1.0.0"} ``` -------------------------------- ### Configure JSON Library (Poison) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/upgrading/0.9.x_to_1.0.x.md If you were using Poison as your JSON library and haven't explicitly configured it, this example shows how to add the :json_library setting to your Vault configuration. ```elixir config :my_app, MyApp.Vault, json_library: Poison, # ... ``` -------------------------------- ### Complete Elixir Schema Example with Encryption and Hashing Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Presents a comprehensive example of an Ecto schema that utilizes both encrypted fields and searchable hash indexes. It includes the definitions for encrypted binary and HMAC modules, a migration to create the table with a hash index, and the schema definition with usage examples for insertion and querying. ```elixir # lib/my_app/encrypted/binary.ex defmodule MyApp.Encrypted.Binary do use Cloak.Ecto.Binary, vault: MyApp.Vault end # lib/my_app/hashed/hmac.ex defmodule MyApp.Hashed.HMAC do use Cloak.Ecto.HMAC, otp_app: :my_app @impl Cloak.Ecto.HMAC def init(_config) do {:ok, [algorithm: :sha512, secret: System.get_env("HMAC_SECRET")]} end end # Migration defmodule MyApp.Repo.Migrations.CreateUsers do use Ecto.Migration def change do create table(:users) do add :name, :string add :email, :binary add :email_hash, :binary timestamps() end create index(:users, [:email_hash]) end end # Schema defmodule MyApp.Accounts.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :name, :string field :email, MyApp.Encrypted.Binary field :email_hash, MyApp.Hashed.HMAC timestamps() end def changeset(struct, attrs \\ %{}) struct |> cast(attrs, [:name, :email]) |> validate_required([:email]) |> put_hashed_fields() end defp put_hashed_fields(changeset) do changeset |> put_change(:email_hash, get_field(changeset, :email)) end end # Usage iex> alias MyApp.{Repo, Accounts.User} # Insert iex> {:ok, user} = %User{} |> User.changeset(%{name: "John", email: "john@example.com"}) |> Repo.insert() %User{id: 1, name: "John", email: "john@example.com", email_hash: <<...>>} # Query by hash iex> Repo.get_by(User, email_hash: "john@example.com") %User{id: 1, name: "John", email: "john@example.com", ...} ``` -------------------------------- ### Define Cloak.Vault with Environment Variable Key Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Define a Cloak.Vault module that retrieves the encryption key from an environment variable (e.g., `CLOAK_KEY`). The `init/1` callback decodes the Base64 encoded key from the environment variable, providing a more flexible configuration. ```elixir defmodule MyApp.Vault do use Cloak.Vault, otp_app: :my_app @impl GenServer def init(config) do config = Keyword.put(config, :ciphers, [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: decode_env!("CLOAK_KEY")} ]) {:ok, config} end defp decode_env!(var) do var |> System.get_env() |> Base.decode64!() end end ``` -------------------------------- ### Define Local Ecto Type for Encrypted Binary Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Define a local Ecto type that uses `Cloak.Ecto.Binary` to handle encrypted binary data. This type is associated with your configured vault (`MyApp.Vault`). ```elixir defmodule MyApp.Encrypted.Binary do use Cloak.Ecto.Binary, vault: MyApp.Vault end ``` -------------------------------- ### Update Cloak Field References (Ecto) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/upgrading/0.9.x_to_1.0.x.md This example demonstrates how to update Cloak field references from the older naming scheme to the new Ecto-specific naming convention in your Elixir code. ```elixir use Cloak.Fields.Binary, vault: MyApp.Vault Should now become: use Cloak.Ecto.Binary, vault: MyApp.Vault ``` -------------------------------- ### Update User Record with Email Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Demonstrates updating a user record using Ecto's changeset and repository. This example shows how to modify a specific field, in this case, the email address, and persist the changes. ```elixir iex> user |> User.changeset(%{email: "john.doe@example.com"}) |> Repo.update() {:ok, %User{email: "john.doe@example.com", ...}} ``` -------------------------------- ### Generate a 256-bit Encryption Key Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Generate a strong, 256-bit encryption key encoded in Base64 using the `:crypto.strong_rand_bytes` function within the IEx console. This key is essential for Cloak.Ecto's encryption capabilities. ```elixir 32 |> :crypto.strong_rand_bytes() |> Base.encode64() # => "aJ7HcM24BcyiwsAvRsa3EG3jcvaFWooyQJ+91OO7bRU=" ``` -------------------------------- ### Configuring Labeled Ciphers in Elixir Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Shows how to configure multiple ciphers with specific labels for different fields in an Ecto schema. This allows for granular control over encryption strategies for sensitive data. The example defines a default cipher and a 'pii' cipher for personally identifiable information. ```elixir # Configuration with multiple ciphers config :my_app, MyApp.Vault, ciphers: [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: Base.decode64!("key1...")}, pii: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.PII", key: Base.decode64!("key2...")} ] # Type with specific label defmodule MyApp.Encrypted.PII do use Cloak.Ecto.Binary, vault: MyApp.Vault, label: :pii end # Schema schema "users" do field :email, MyApp.Encrypted.Binary # Uses :default cipher field :ssn, MyApp.Encrypted.PII # Uses :pii cipher end ``` -------------------------------- ### Ecto Schema with Encrypted and Hashed Fields Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/install.md Define an Ecto schema for a 'users' table, including fields for encrypted data (`email`) and a hashed version for querying (`email_hash`). The `changeset` function handles casting and populating the hashed field. ```elixir defmodule MyApp.Accounts.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :email, MyApp.Encrypted.Binary field :email_hash, MyApp.Hashed.HMAC # ... other fields timestamps() end @doc false def changeset(struct, attrs \\ %{}) do struct |> cast(attrs, [:email]) |> put_hashed_fields() end defp put_hashed_fields(changeset) do changeset |> put_change(:email_hash, get_field(changeset, :email)) end end ``` -------------------------------- ### Encrypting Existing Data in Elixir with Ecto Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Provides a step-by-step guide to migrate unencrypted fields to encrypted fields in an existing Ecto schema. This involves adding new encrypted fields, updating the schema and changeset to handle both fields temporarily, copying data, and finally removing the old unencrypted field. ```elixir # Step 1: Add encrypted fields defmodule MyApp.Repo.Migrations.AddEncryptedFields do use Ecto.Migration def change do alter table(:users) do add :encrypted_email, :binary end end end # Step 2: Update schema with both fields temporarily defmodule MyApp.Accounts.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :email, :string field :encrypted_email, MyApp.Encrypted.Binary end def changeset(struct, attrs \\ %{}) struct |> cast(attrs, [:email]) |> put_encrypted_fields() end defp put_encrypted_fields(changeset) do changeset |> put_change(:encrypted_email, get_field(changeset, :email)) end end # Step 3: Copy data (in IEx or mix task) MyApp.Accounts.User |> MyApp.Repo.all() |> Enum.each(fn user -> user |> Ecto.Changeset.change(%{encrypted_email: user.email}) |> MyApp.Repo.update!() end) # Step 4: Remove old field and rename defmodule MyApp.Repo.Migrations.RemoveUnencryptedFields do use Ecto.Migration def change do alter table(:users) do remove :email end rename table(:users), :encrypted_email, to: :email end end # Step 5: Final schema defmodule MyApp.Accounts.User do use Ecto.Schema schema "users" do field :email, MyApp.Encrypted.Binary end end ``` -------------------------------- ### Unwrap Encrypted Value in Elixir Function Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/closure_wrapping.md This Elixir code snippet illustrates how to unwrap a plaintext value from a zero-arity closure, which was created using the `closure: true` option in Cloak Ecto. The example shows unwrapping a password closure within an `HTTPClient.basic_auth` call. It also includes a `rescue` block that uses `Plug.Crypto.prune_args_from_stacktrace/1` to prevent sensitive arguments from leaking into stacktraces in case of exceptions. ```elixir def basic_auth(req, client) do # Unwrap string value from password closure HTTPClient.basic_auth(req, client.username, client.password.()) rescue e -> reraise e, Plug.Crypto.prune_args_from_stacktrace(System.stacktrace()) end ``` -------------------------------- ### Add Jason Dependency Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/upgrading/0.9.x_to_1.0.x.md If you are not specifying a JSON library and want to use Jason (the new default), you need to add it to your project's dependencies. ```elixir {:jason, "~> 1.0"} ``` -------------------------------- ### Configure Cloak.Ecto Vault with Runtime Configuration Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Configures the Cloak Vault at runtime using an `init/1` callback. This allows for dynamic configuration, such as fetching encryption keys from environment variables. ```elixir defmodule MyApp.Vault do use Cloak.Vault, otp_app: :my_app @impl GenServer def init(config) do config = Keyword.put(config, :ciphers, [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: decode_env!("CLOAK_KEY")} ]) {:ok, config} end defp decode_env!(var) do var |> System.get_env() |> Base.decode64!() end end # Add to supervision tree in application.ex children = [ MyApp.Vault ] ``` -------------------------------- ### Create Secure PBKDF2 Hashes with Cloak.Ecto.PBKDF2 Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Generates PBKDF2 hashes with key stretching, providing the most secure option for hashing. Requires the pbkdf2 dependency and can be configured statically or at runtime. ```elixir # Requires pbkdf2 dependency # {:pbkdf2, "~> 2.0", github: "miniclip/erlang-pbkdf2"} defmodule MyApp.Hashed.PBKDF2 do use Cloak.Ecto.PBKDF2, otp_app: :my_app end # Configuration config :my_app, MyApp.Hashed.PBKDF2, algorithm: :sha256, iterations: 600_000, secret: "your-pbkdf2-secret", size: 64 # Or with runtime configuration defmodule MyApp.Hashed.PBKDF2 do use Cloak.Ecto.PBKDF2, otp_app: :my_app @impl Cloak.Ecto.PBKDF2 def init(config) do config = Keyword.merge(config, [ algorithm: :sha256, iterations: 600_000, secret: System.get_env("PBKDF2_SECRET"), size: 64 ]) {:ok, config} end end # Schema schema "users" do field :email, MyApp.Encrypted.Binary field :email_hash, MyApp.Hashed.PBKDF2 end ``` -------------------------------- ### Update Migration References Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/upgrading/0.9.x_to_1.0.x.md This shows the renaming of migration references. If you were using 'mix cloak.migrate', you should now use 'mix cloak.migrate.ecto'. If directly referencing 'Cloak.Migrator', rename it to 'Cloak.Ecto.Migrator'. ```shell mix cloak.migrate Should now become: mix cloak.migrate.ecto ``` -------------------------------- ### Migrate Data Using Mix Cloak Migrate Ecto (Elixir) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/rotate_keys.md Shows how to use the `mix cloak.migrate.ecto` task to migrate data to the new encryption key. This can be done for a specific repository and schema, or globally by configuring `cloak_repo` and `cloak_schemas`. ```bash mix cloak.migrate.ecto -r MyApp.Repo -s MyApp.Schema ``` ```elixir config :my_app, cloak_repo: MyApp.Repo, cloak_schemas: [...] ``` ```bash mix cloak.migrate.ecto ``` -------------------------------- ### Configure Cloak.Ecto Vault with Static Configuration Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Sets up the Cloak Vault for encryption using static configuration in `config.exs`. It specifies the JSON library and encryption ciphers, including a default AES.GCM cipher with a base64 encoded key. ```elixir defmodule MyApp.Vault do use Cloak.Vault, otp_app: :my_app end # config/config.exs - Static configuration config :my_app, MyApp.Vault, json_library: Jason, ciphers: [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: Base.decode64!("3Jnb0hZiHIzHTOih7t2cTEPEpY98Tu1wvQkPfq/XwqE=")} ] ``` -------------------------------- ### Generate Encryption Keys using Erlang Crypto Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Demonstrates how to generate a strong 256-bit (32-byte) encryption key using Erlang's `:crypto.strong_rand_bytes/1` function and encode it to base64 for use in configuration. ```elixir # In IEx console iex> 32 |> :crypto.strong_rand_bytes() |> Base.encode64() "aJ7HcM24BcyiwsAvRsa3EG3jcvaFWooyQJ+91OO7bRU=" # The key must be decoded when used in configuration key: Base.decode64!("aJ7HcM24BcyiwsAvRsa3EG3jcvaFWooyQJ+91OO7bRU=") ``` -------------------------------- ### Create Searchable HMAC Hashes with Cloak.Ecto.HMAC Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Generates deterministic HMAC hashes for searching encrypted fields, offering more security than SHA256. Configuration can be static or runtime. ```elixir defmodule MyApp.Hashed.HMAC do use Cloak.Ecto.HMAC, otp_app: :my_app end # Configuration config :my_app, MyApp.Hashed.HMAC, algorithm: :sha512, secret: "your-hmac-secret-key" # Or with runtime configuration defmodule MyApp.Hashed.HMAC do use Cloak.Ecto.HMAC, otp_app: :my_app @impl Cloak.Ecto.HMAC def init(config) do config = Keyword.merge(config, [ algorithm: :sha512, secret: System.get_env("HMAC_SECRET") ]) {:ok, config} end end # Migration add :email, :binary add :email_hash, :binary # Schema with both encrypted and hash fields schema "users" do field :email, MyApp.Encrypted.Binary field :email_hash, MyApp.Hashed.HMAC end # Changeset to keep hash in sync def changeset(struct, attrs \\ %{}) struct |> cast(attrs, [:email]) |> put_hashed_fields() end defp put_hashed_fields(changeset) do changeset |> put_change(:email_hash, get_field(changeset, :email)) end # Query by hash instead of encrypted field iex> MyApp.Repo.get_by(MyApp.Accounts.User, email_hash: "user@example.com") %MyApp.Accounts.User{email: "user@example.com", email_hash: <<115, 6, 45, ...>>} ``` -------------------------------- ### Key Rotation with Cloak Ecto Migration Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Details the process of rotating encryption keys for existing data using the `mix cloak.migrate.ecto` task. This involves updating the configuration to include new and retired keys, running the migration, and finally removing the retired key. This ensures zero downtime during key rotation. ```elixir # Step 1: Add new key as default, demote old key config :my_app, MyApp.Vault, ciphers: [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V2", key: Base.decode64!("new_key...")}, retired: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: Base.decode64!("old_key...")} ] # Step 2: Run migration for each schema # $ mix cloak.migrate.ecto -r MyApp.Repo -s MyApp.Accounts.User # Or configure multiple schemas config :my_app, cloak_repo: MyApp.Repo, cloak_schemas: [MyApp.Accounts.User, MyApp.Posts.Post] # $ mix cloak.migrate.ecto # Step 3: After migration completes, remove retired key config :my_app, MyApp.Vault, ciphers: [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V2", key: Base.decode64!("new_key...")} ] ``` -------------------------------- ### Generate Encryption Key in IEx Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/generate_keys.md This snippet demonstrates how to generate a strong 256-bit encryption key using Elixir's IEx console. It utilizes the `:crypto.strong_rand_bytes/1` function to produce random bytes and `Base.encode64/1` to encode them, making the key suitable for configuration. ```elixir 32 |> :crypto.strong_rand_bytes() |> Base.encode64() ``` -------------------------------- ### Add New Key to Vault Configuration (Elixir) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/rotate_keys.md Demonstrates how to add a new encryption key to the `:ciphers` list in your Cloak Ecto vault configuration. The new key should be the first in the list, and the old key should be demoted to `:retired`. ```elixir config :my_app, MyApp.Vault, ciphers: [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V2", key: <<...>>}, retired: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: <<...>>} ] ``` -------------------------------- ### Database Interaction with Encrypted Fields Source: https://github.com/danielberkompas/cloak_ecto/blob/master/README.md These Elixir code snippets illustrate the behavior of Cloak.Ecto during database operations. The first shows an `INSERT` query where the plaintext value is automatically encrypted into a binary blob before being stored. The second shows a `Repo.get` operation where the encrypted binary is automatically decrypted back into its original plaintext form. ```elixir iex> Repo.insert!(%MyApp.EctoSchema{encrypted_field: "plaintext"}) 08:46:08.862 [debug] QUERY OK db=3.4ms INSERT INTO "table_name" ("encrypted_field") VALUES ($1) RETURNING "id", "encrypted_field" [ <<1,10, 65, 69, 83, 46, 67, 84, 82, 46, 86, 49, 69, 92, 173, 219, 203, 238, 26, 58, 236, 5, 104, 23, 12, 10, 182, 31, 221, 89, 22, 58, 34, 79, 109, 30, 70, 254, 56, 93, 102, 84>> ] ``` ```elixir iex> Repo.get(MyApp.EctoSchema, 1) %MyApp.EctoSchema{encrypted_field: "plaintext"} ``` -------------------------------- ### Create Simple SHA256 Hashes with Cloak.Ecto.SHA256 Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Generates SHA256 hashes for searching, which is less secure than HMAC as it does not use a secret key. No explicit configuration is needed. ```elixir # No configuration needed - can be used directly schema "users" do field :email, MyApp.Encrypted.Binary field :email_hash, Cloak.Ecto.SHA256 end # Changeset def changeset(struct, attrs \\ %{}) struct |> cast(attrs, [:email]) |> put_change(:email_hash, get_field(changeset, :email)) end # Query iex> MyApp.Repo.get_by(MyApp.Accounts.User, email_hash: "user@example.com") %MyApp.Accounts.User{email: "user@example.com", ...} ``` -------------------------------- ### Encrypt String/Binary Fields with Cloak.Ecto.Binary Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts string or binary data transparently. Requires defining a custom Ecto type module that uses `Cloak.Ecto.Binary` and specifying the `:binary` type in Ecto migrations. ```elixir # Define your encrypted type defmodule MyApp.Encrypted.Binary do use Cloak.Ecto.Binary, vault: MyApp.Vault end # Migration - must use :binary type defmodule MyApp.Repo.Migrations.CreateUsers do use Ecto.Migration def change do create table(:users) do add :email, :binary timestamps() end end end # Schema definition defmodule MyApp.Accounts.User do use Ecto.Schema schema "users" do field :email, MyApp.Encrypted.Binary timestamps() end end # Usage - encryption/decryption is automatic iex> user = %MyApp.Accounts.User{email: "user@example.com"} iex> MyApp.Repo.insert!(user) # Database stores: <<1, 10, 65, 69, 83, 46, 71, 67, 77, ...>> (encrypted blob) iex> MyApp.Repo.get(MyApp.Accounts.User, 1) %MyApp.Accounts.User{email: "user@example.com"} # Automatically decrypted ``` -------------------------------- ### Use Custom Encrypted Type in Ecto Schema Source: https://github.com/danielberkompas/cloak_ecto/blob/master/README.md This Elixir code demonstrates how to integrate the custom encrypted binary type (`MyApp.Encrypted.Binary`) into an Ecto schema. By defining a field with this type, Cloak.Ecto automatically handles the encryption when data is written to the database and decryption when data is read. ```elixir defmodule MyApp.EctoSchema do use Ecto.Schema schema "table_name" do field :encrypted_field, MyApp.Encrypted.Binary # ... end end ``` -------------------------------- ### Encrypt Float Fields with Cloak.Ecto.Float Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts floating-point numbers transparently. Use `Cloak.Ecto.Decimal` for applications requiring precise decimal arithmetic. The migration uses `:binary`, and the schema uses `Cloak.Ecto.Float`. ```elixir defmodule MyApp.Encrypted.Float do use Cloak.Ecto.Float, vault: MyApp.Vault end # Migration add :rating, :binary # Schema schema "products" do field :rating, MyApp.Encrypted.Float end # Usage iex> product = %MyApp.Product{rating: 4.5} iex> MyApp.Repo.insert!(product) iex> MyApp.Repo.get(MyApp.Product, 1).rating 4.5 ``` -------------------------------- ### Encrypt String List with Cloak.Ecto.StringList Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts lists of strings using JSON serialization. This is useful for storing tags or categories. Requires a migration and schema definition. ```elixir defmodule MyApp.Encrypted.StringList do use Cloak.Ecto.StringList, vault: MyApp.Vault end # Migration add :tags, :binary # Schema schema "posts" do field :tags, MyApp.Encrypted.StringList end # Usage iex> post = %MyApp.Post{tags: ["elixir", "encryption", "ecto"]} iex> MyApp.Repo.insert!(post) iex> MyApp.Repo.get(MyApp.Post, 1).tags ["elixir", "encryption", "ecto"] ``` -------------------------------- ### Encrypt Decimal Fields with Cloak.Ecto.Decimal Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts `Decimal` values with full precision, suitable for financial data. The migration uses `:binary`, and the schema defines the field using `Cloak.Ecto.Decimal`, ensuring accurate representation. ```elixir defmodule MyApp.Encrypted.Decimal do use Cloak.Ecto.Decimal, vault: MyApp.Vault end # Migration add :balance, :binary # Schema schema "accounts" do field :balance, MyApp.Encrypted.Decimal end # Usage iex> account = %MyApp.Account{balance: Decimal.new("1234.56")} iex> MyApp.Repo.insert!(account) iex> MyApp.Repo.get(MyApp.Account, 1).balance #Decimal<1234.56> ``` -------------------------------- ### Encrypt Date Fields with Cloak.Ecto.Date Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts `Date` values using ISO8601 serialization for storage. The migration requires the `:binary` type, and the schema utilizes the `Cloak.Ecto.Date` custom type for transparent encryption and decryption. ```elixir defmodule MyApp.Encrypted.Date do use Cloak.Ecto.Date, vault: MyApp.Vault end # Migration add :birth_date, :binary # Schema schema "users" do field :birth_date, MyApp.Encrypted.Date end ``` -------------------------------- ### Encrypt Integer Fields with Cloak.Ecto.Integer Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts integer values transparently, handling automatic type conversion. The migration must use the `:binary` type, and the schema defines the field using the custom `Cloak.Ecto.Integer` type. ```elixir defmodule MyApp.Encrypted.Integer do use Cloak.Ecto.Integer, vault: MyApp.Vault end # Migration add :age, :binary # Schema schema "users" do field :age, MyApp.Encrypted.Integer end # Usage iex> user = %MyApp.Accounts.User{age: 25} iex> MyApp.Repo.insert!(user) iex> MyApp.Repo.get(MyApp.Accounts.User, 1).age 25 # Returns integer, not string ``` -------------------------------- ### Encrypt DateTime with Cloak.Ecto.DateTime Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts UTC DateTime values using ISO8601 serialization. Requires a vault configuration and defines an Ecto schema field for encrypted last_login. ```elixir defmodule MyApp.Encrypted.DateTime do use Cloak.Ecto.DateTime, vault: MyApp.Vault end # Migration add :last_login, :binary # Schema schema "users" do field :last_login, MyApp.Encrypted.DateTime end # Usage iex> user = %MyApp.Accounts.User{last_login: ~U[2024-01-15 10:30:00Z]} iex> MyApp.Repo.insert!(user) iex> MyApp.Repo.get(MyApp.Accounts.User, 1).last_login ~U[2024-01-15 10:30:00Z] ``` -------------------------------- ### Encrypt Map with Cloak.Ecto.Map Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Encrypts map data using JSON serialization. Atom keys are converted to string keys upon reading. Requires JSON library configuration in the vault. ```elixir defmodule MyApp.Encrypted.Map do use Cloak.Ecto.Map, vault: MyApp.Vault end # Requires json_library configuration in vault config :my_app, MyApp.Vault, json_library: Jason, ciphers: [...] # Add your ciphers here # Migration add :metadata, :binary # Schema schema "users" do field :metadata, MyApp.Encrypted.Map end # Usage iex> user = %MyApp.Accounts.User{metadata: %{role: "admin", permissions: ["read", "write"]}} iex> MyApp.Repo.insert!(user) iex> MyApp.Repo.get(MyApp.Accounts.User, 1).metadata %{"role" => "admin", "permissions" => ["read", "write"]} ``` -------------------------------- ### Copy Data to Encrypted Fields (Elixir) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/encrypt_existing_data.md This Elixir code snippet demonstrates how to iterate through all user records, copy the data from the original 'name' and 'metadata' fields to their respective 'encrypted_' fields using Ecto.Changeset.change, and then update the records in the database using MyApp.Repo.update!(). This is typically run in a mix task or IEx console. ```elixir MyApp.Accounts.User |> MyApp.Repo.all() |> Enum.map(fn user -> user |> Ecto.Changeset.change(%{ encrypted_name: user.name, encrypted_metadata: user.metadata }) |> MyApp.Repo.update!() end) ``` -------------------------------- ### Decrypting Encrypted Values in Elixir Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Demonstrates how to retrieve and decrypt values stored using Cloak Ecto. The decrypted value is initially wrapped in a closure and needs to be called to access the actual data. This is useful for secure handling of sensitive information like passwords. ```elixir iex> client = MyApp.Repo.get(MyApp.Client, 1) iex> client.password #Function<...> # Unwrap when needed iex> client.password.() "secret_password" # Safe HTTP client usage def basic_auth(req, client) do HTTPClient.basic_auth(req, client.username, client.password.()) rescue e -> reraise e, Plug.Crypto.prune_args_from_stacktrace(System.stacktrace()) end ``` -------------------------------- ### Remove Retired Key from Vault Configuration (Elixir) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/rotate_keys.md Illustrates the final step of removing the retired encryption key from the Cloak Ecto vault configuration after all data has been migrated and verified. ```elixir config :my_app, MyApp.Vault, ciphers: [ default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V2", key: <<...>>}, ] ``` -------------------------------- ### Add Encrypted Fields to Database Schema (Ecto Migration) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/encrypt_existing_data.md This Ecto migration code adds new binary fields prefixed with 'encrypted_' to the 'users' table. These fields will store the encrypted versions of the original 'name' and 'metadata' fields. This is a temporary step during the data encryption process. ```elixir alter table(:users) do add :encrypted_name, :binary add :encrypted_metadata, :binary end ``` -------------------------------- ### Define Cloak Ecto Type with Closure Wrapping (Elixir) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/closure_wrapping.md This snippet demonstrates how to define a custom Ecto type using Cloak.Ecto.Binary with the `closure: true` option. This option ensures that decrypted values are wrapped in a zero-arity closure, preventing accidental plaintext leakage in contexts such as stacktraces, Inspect documents, and JSON serializations. The `vault` option specifies the Vault module to be used. ```elixir defmodule MyApp.Encrypted.WrappedBinary do use Cloak.Ecto.Binary, vault: MyApp.Vault, closure: true end ``` -------------------------------- ### Remove Original Fields and Rename Encrypted Fields (Ecto Migration) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/encrypt_existing_data.md This Ecto migration code removes the original unencrypted 'name' and 'metadata' fields from the 'users' table. It then renames the 'encrypted_name' field to 'name' and 'encrypted_metadata' to 'metadata', completing the transition to encrypted fields. ```elixir alter table(:users) do remove :name remove :metadata end rename table(:users), :encrypted_name, to: :name rename table(:users), :encrypted_metadata, to: :metadata ``` -------------------------------- ### Fix Ecto Default Value Validation Error with Cloak Ecto Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/troubleshooting.md This code snippet demonstrates how to resolve an 'ArgumentError' when Ecto 3.6+ attempts to validate default values for fields using Cloak Ecto. The solution involves adding the `:skip_default_validation` option to the field definition. ```elixir field :name, MyApp.Encrypted.Binary, default: "foo", skip_default_validation: true ``` -------------------------------- ### Update Ecto Schema with Encrypted Fields and Temporary Changeset Function (Elixir) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/encrypt_existing_data.md This Elixir code defines an Ecto schema for a 'User' module. It includes both original fields and new 'encrypted_' fields. A temporary `put_encrypted_fields` function is added to the changeset to copy data from original fields to their encrypted counterparts during the migration phase. ```elixir defmodule MyApp.Accounts.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :name, :string field :encrypted_name, MyApp.Encrypted.Binary field :metadata, :map field :encrypted_metadata, MyApp.Encrypted.Map end @doc false def changeset(struct, attrs \\ %{}) do struct |> cast(attrs, [:name, :metadata]) |> put_encrypted_fields() end # Temporary function during the migration process, to ensure # that all changes are copied over to the new fields defp put_encrypted_fields(changeset) do changeset |> put_change(:encrypted_name, get_field(changeset, :name)) |> put_change(:encrypted_metadata, get_field(changeset, :metadata)) end end ``` -------------------------------- ### Prevent Plaintext Leakage with Closure Wrapping Source: https://context7.com/danielberkompas/cloak_ecto/llms.txt Wraps decrypted values in closures to prevent accidental exposure in logs and stacktraces. This enhances security by limiting the visibility of sensitive data. ```elixir defmodule MyApp.Encrypted.WrappedBinary do use Cloak.Ecto.Binary, vault: MyApp.Vault, closure: true end # Schema schema "clients" do field :password, MyApp.Encrypted.WrappedBinary end ``` -------------------------------- ### Final Ecto Schema After Encryption Migration (Elixir) Source: https://github.com/danielberkompas/cloak_ecto/blob/master/guides/how_to/encrypt_existing_data.md This Elixir code represents the final Ecto schema for the 'User' module after the data encryption migration is complete. The temporary 'encrypted_' fields are now the primary fields, and the `put_encrypted_fields` function has been removed from the changeset. ```elixir defmodule MyApp.Accounts.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :name, MyApp.Encrypted.Binary field :metadata, MyApp.Encrypted.Map end @doc false def changeset(struct, attrs \\ %{}) do struct |> cast(attrs, [:name, :metadata]) end end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.