adds set_authorizer/2 (fixes #344)#345
Conversation
01fbd31 to
57212d2
Compare
57212d2 to
a6206ef
Compare
| // Denied authorizer action codes. Sized to 64 for margin — highest | ||
| // currently defined SQLite action code is SQLITE_RECURSIVE (33). | ||
| #define AUTHORIZER_DENY_SIZE 64 |
There was a problem hiding this comment.
Are you able to come up with a test that reaches the max deny size of 33? I just want to ensure a segfault does not occur.
|
Added braces and an array exhaustion test that denies all 31 action codes at once including :recursive (code 33, the highest index). This way if someone shrinks AUTHORIZER_DENY_SIZE below 34 the test fails in CI rather than silently passing and segfaulting at runtime. The list can't be generated programmatically since the atom-to-code mapping lives in C and the test in Elixir, but the SQLite action code list hasn't changed since 3.8.3 (2014). And if a new code is ever added, action_code_from_atom needs updating anyway. |
I mean, anything is possible but we'd have to pass a shared source of truth across the NIF barrier and it would be code that exists only for testing purposes |
warmwaffles
left a comment
There was a problem hiding this comment.
I don't see anything wrong with this. Thank you for implementing.
|
We could static assert that the |
|
Also I appreciate the honesty about he AI generation 😉 |
|
I'm gonna merge this and toy with it some. I'll ping back here when I cut a release for it. |
|
Memory consumption wise, we could probably use a 64 bit unsigned integer and bit shift with flags. |
|
Made some corrections, and will be released under v0.36.0 |
|
Sounds great, I didn't have time to think about your other comments yet but you know this codebase infinitely better than I do so I'm sure it'll work 😸 |
|
I'll leave the bit shifting thing until later. There's some overhead, ever so slight by authorizing every action and jumping the list in memory, as opposed to a bit check. Let me know if you see degraded performance. |
Adds
Exqlite.Sqlite3.set_authorizer/2which registers a deny-list authorizer viasqlite3_set_authorizer(). The caller passes a list of action atoms to block (e.g.[:attach, :detach]), and a static C callback denies those action codes duringsqlite3_prepare(). Pass an empty list to clear the authorizer.A full Erlang callback isn't practical here since the authorizer is called synchronously during
sqlite3_prepare()and must return immediately. The deny-list approach avoids this as config is stored in the connection struct as a flatint[64]array indexed by action code and the callback is a single bounds check and array lookup with no allocation.Implementation notes:
set_update_hookArgumentErrorwithout modifying the existing authorizerSince this feature is likely to be used in security-sensitive contexts I'd appreciate a careful review of the C code. I'm not the most experienced C developer and this touches the security boundary of the library.
PR description written mostly by AI so if it sounds like slop it's because it is