Filter by encrypted attribute

I am storing some personal information (national identification numbers,), and encrypting it with ash_cloak. I'd like to implement an action where I search for users given a national identification number as an argument. With the filter
filter expr(national_identity_number == ^arg(:query))
filter expr(national_identity_number == ^arg(:query))
I get this error:
** (Ash.Error.Invalid)
Invalid Error

* national_identity_number cannot be referenced in filters
at filter
(ash 3.5.26) lib/ash/error/query/invalid_filter_reference.ex:4: Ash.Error.Query.InvalidFilterReference.exception/1
(ash 3.5.26) lib/ash/filter/filter.ex:391: anonymous fn/2 in Ash.Filter.validate_references/2
(elixir 1.18.4) lib/enum.ex:4442: Enum.flat_map_list/2
# further stack trace cut
** (Ash.Error.Invalid)
Invalid Error

* national_identity_number cannot be referenced in filters
at filter
(ash 3.5.26) lib/ash/error/query/invalid_filter_reference.ex:4: Ash.Error.Query.InvalidFilterReference.exception/1
(ash 3.5.26) lib/ash/filter/filter.ex:391: anonymous fn/2 in Ash.Filter.validate_references/2
(elixir 1.18.4) lib/enum.ex:4442: Enum.flat_map_list/2
# further stack trace cut
Is there any way to accomplish this?
3 Replies
ZachDaniel
ZachDaniel2mo ago
You should be able to do something like this:
prepare fn query, _ ->
value = encrypt(query.arguments[:query])
Ash.Query.filter(query, encrypted_national_identity_number == ^value)
end
prepare fn query, _ ->
value = encrypt(query.arguments[:query])
Ash.Query.filter(query, encrypted_national_identity_number == ^value)
end
EAJ
EAJOP2mo ago
After messing with it for a bit I ended up with this:
prepare fn query, _ ->
encrypted_query_string =
AshCloak.do_encrypt(__MODULE__, Ash.CiString.value(query.arguments[:query]))

Ash.Query.set_context(query, %{encrypted_query: encrypted_query_string})
end

filter expr(encrypted_national_identity_number == ^context(:encrypted_query))
prepare fn query, _ ->
encrypted_query_string =
AshCloak.do_encrypt(__MODULE__, Ash.CiString.value(query.arguments[:query]))

Ash.Query.set_context(query, %{encrypted_query: encrypted_query_string})
end

filter expr(encrypted_national_identity_number == ^context(:encrypted_query))
However I realized that I'm encrypting with a new random IV every time, so it won't work. I'll have to think about it, I suppose the options are 1. Drop the search 2. Decrypt the field for each record every time a search is run 3. Use a deterministic encryption 4. Drop the encryption
ZachDaniel
ZachDaniel2mo ago
Yeah that makes sense. It's not realistic to filter otherwise, unless you use encryption designed to work that way There are some things that work directly in the db that support filtering I think

Did you find this page helpful?