sc4224
Verifying Signature from request header in elixir
I have a typeform request where I need to verify the signature manually. :crypto.hmac is always returning an error.
No sure what I’m doing wrong here:
defmodule ApiWeb.PageController do
use ApiWeb, :controller
def index(conn, _params) do
conn
|> verify_signature
send_resp(conn, 201, "")
end
defp verify_signature(conn) do
{:ok, body, conn} = Plug.Conn.read_body(conn)
my_signature = :crypto.hmac(:sha256, System.get_env("TYPEFORM_SECRET"), body) |> Base.encode16 |> String.downcase
[typeform_signature] = conn |> get_req_header("Typeform-Signature")
Plug.Crypto.secure_compare(my_signature, typeform_signature)
end
end
Here’s the error returned
** (exit) an exception was raised:
** (ArgumentError) argument error
(crypto 4.7) crypto.erl:978: :crypto.hmac/3
(api 0.1.0) lib/api_web/controllers/page_controller.ex:14: ApiWeb.PageController.verify_signature/1
(api 0.1.0) lib/api_web/controllers/page_controller.ex:6: ApiWeb.PageController.index/2
(api 0.1.0) lib/api_web/controllers/page_controller.ex:1: ApiWeb.PageController.action/2
(api 0.1.0) lib/api_web/controllers/page_controller.ex:1: ApiWeb.PageController.phoenix_controller_pipeline/2
(phoenix 1.5.3) lib/phoenix/router.ex:352: Phoenix.Router.call/2
(api 0.1.0) lib/api_web/endpoint.ex:1: ApiWeb.Endpoint.plug_builder_call/2
(api 0.1.0) lib/plug/debugger.ex:132: ApiWeb.Endpoint.“call (overridable 3)”/2
(api 0.1.0) lib/api_web/endpoint.ex:1: ApiWeb.Endpoint.call/2
(phoenix 1.5.3) lib/phoenix/endpoint/cowboy2_handler.ex:65: Phoenix.Endpoint.Cowboy2Handler.init/4
(cowboy 2.7.0) api/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy 2.7.0) api/deps/cowboy/src/cowboy_stream_h.erl:320: :cowboy_stream_h.execute/3
(cowboy 2.7.0) api/deps/cowboy/src/cowboy_stream_h.erl:302: :cowboy_stream_h.request_process/3
(stdlib 3.13) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Marked As Solved
idi527
You don’t need to call your module. You can access the raw body contents in the conn.
If your cache body reader module is like this:
defmodule CacheBodyReader do
def read_body(conn, opts) do
{:ok, body, conn} = Plug.Conn.read_body(conn, opts)
conn = update_in(conn.assigns[:raw_body], &[body | (&1 || [])])
{:ok, body, conn}
end
end
then you can access your raw body in conn.assigns.raw_body. Note that you probably don’t need to save the body for every request, but only for those that need it. I usually put some conditions on conn.path_name to decide if there is a need to save the raw body.
Also Liked
idi527

{:ok, body, conn} = Plug.Conn.read_body(conn) probably returns {:ok, nil, conn} and passing nil to :crypto.hmac/3 causes the error.
This is because it’s only possible to read the body once, and plug Plug.Parsers already does it (it’s in your endpoint.ex). The workaround is a custom body reader which caches the raw body contents.
sc4224
ok thanks I got my problem solved. Really appreciate it man







