Skip to content

Conversation

@hickscorp
Copy link

@hickscorp hickscorp commented Sep 29, 2025

Ok so - unable to use this for embeds or anything that stores into JSON or JSONB at database / field level.
That's because non-standard strings aren't possible to express without heavy escaping in JSON.
So why not wrap them into a B64 step?

Super-useful if you want to be able to use it in an embedded_schema...

Ah yeah also as a side note - if you have def embed_as(_), do: :self then Ecto will skip the dump and load calls silently. Not great, as it means that users who use Fields.Encrypted* types won't know that they in fact aren't encrypting anything... I checked myself.
So to force Ecto to load / dump, I used def embebd_as(_), do: :dump and it seems to work for embeds as well now.

@hickscorp hickscorp force-pushed the features/base-64-encrypted branch from 93562be to 5e709b6 Compare September 29, 2025 15:55
@hickscorp hickscorp force-pushed the features/base-64-encrypted branch from 5e709b6 to bfcd9ea Compare September 29, 2025 16:25
def embed_as(_),
do: :dump

def equal?(term1, term2),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ecto will skip dumping and loading if this is set to :self.

# We got nil from the database... Just use that.
nil -> value
# We got any binary. Decode64 and decrypt.
<<>> <> _ -> value |> Base.decode64!(padding: true) |> AES.decrypt()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a final version, probably we want to avoid the bang function. This is just to show how it would work!

Copy link
Member

@nelsonic nelsonic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hickscorp looks like a good addition. Running the workflow. 👌

@hickscorp
Copy link
Author

hickscorp commented Sep 30, 2025

@hickscorp looks like a good addition. Running the workflow. 👌

Haha thank you - but as much as I appreciate that this would be useful, it's in no state to reach your codebase and was meant as a prototype / example.

A few things, in case still of interest:

  • No modularity at all. It adds a sample EncryptedBase64 type that uses b64 under the hood, but then you'd have to duplicate this into as many other modules (email, password, etc). Instead, it should not be a dedicated sample module, but an option you can pass to the type - somehow.
  • Not everyone want b64! It is useful in particular for embeds (because they're backed by JSON which doesn't binary) - so this one is really just useful for certain use cases but not all.
  • Using a bang function in load is really not a good idea :) we should go with with and normalize the error cases.
  • There are no tests :)
  • Whether we would refactor b64 to become "supported" by the existing types (encrypted password, encrypted email, etc), we would need to make sure it's backward compatible with whatever exists in databases for folks already using bespoke types. Not a big effort, but still something important.

So. I unfortunately don't have enough time now, as I'm prototyping a product and just needed this "quick and dirty". If you want to do it, please take over my PR by all means! Otherwise I can do it later, but I can't guarantee when.

Please don't merge this nasty code of mine, it's really meant as a proof of concept.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants