The Legacy API message lookup endpoints parsed the request body as JSON and
passed the `id` parameter straight through to the message database. A JSON
object supplied for `id` arrived as a Ruby Hash and was used as a raw set of
SQL `WHERE` conditions. `hash_to_sql` interpolated each Hash key directly
inside backtick identifier quoting while escaping only the value, so a key
containing a backtick could break out of the identifier and inject arbitrary
SQL into the SELECT (blind, time-based) against the message database.
Fixes:
- Escape all identifiers (columns, tables, database names) through a new
`escape_identifier` helper that wraps in backticks and doubles embedded
backticks. Applied across hash_to_sql, select, insert, insert_multi,
update and delete so no caller can inject via an identifier.
- Validate the Legacy API `id` parameter at the controller boundary: reject
any non-scalar value before it reaches the database and coerce it to an
integer. Internal Hash-based lookups (e.g. tracking middleware) are
unaffected.
Adds regression tests at the unit (hash_to_sql / escape_identifier) and
request (legacy messages/deliveries) levels.