Encrypted attributes

Some time ago I created a gem adding encrypted attributes to relations using custom types. It is designed to be compatible with ActiveRecord encryption, in case you’re moving from ActiveRecord-powered database to ROM. For now quite a few features from ActiveRecord::Encryption are missing, but basic stuff is working and I think it can already be used.

Here’s a link to the repo: GitHub - katafrakt/rom_encrypted_attribute: RomEncryptedAttribute: Rails-compatible encrypted attributes for ROM

Example usage:

class SecretNotes < ROM::Relation[:sql]
  EncryptedString, EncryptedStringReader =
      primary_key: ENV["ENCRYPTION_PRIMARY_KEY"],
      key_derivation_salt: ENV["ENCRYPTION_KEY_DERIVATION_SALT"]
  schema(:secret_notes, infer: true) do
    attribute :content, EncryptedString, read: EncryptedStringReader

Looking for feedback. Thanks!

1 Like

Thanks for sharing this :slight_smile: Looks very useful. I’d only recommend renaming gem to rom-encrypted_attribute and then following a standard naming convention so ROM::EncryptedAttribute. Another thing to consider is adding a schema plugin to streamline the DX.

I guess I inadvertently followed the Elixir’s rule of “no namespace trespassing”. But if you feel it’s better name, I can change it for sure.

Interesting idea! I had to read the code a bit to understand what the schema plugin is, but I think this is a really good potential improvement here. Thanks!

I got it working via a plugin, but I’m not sure I’m fully happy with that. This is how it looks:

class SecretNotes < ::ROM::Relation[:sql]
  schema(:secret_notes, infer: true) do
    use :encrypted_attributes, primary_key: ENV["ENCRYPTION_PRIMARY_KEY"],
      key_derivation_salt: ENV["ENCRYPTION_KEY_DERIVATION_SALT"]
    encrypt :content, :title

What I don’t like here is that I’d have to pass primary key and key derivation salt every time I want to use encryption in a schema. This does not sound like a good developer experience. Is there, perhaps, a way to set something like a plugin global setting, which would be taken as a default if the configuration is not provided via use DSL?