defmodule TuskerPushWeb.PushController do alias TuskerPush.Forwarder use TuskerPushWeb, :controller require Logger def push(conn, %{"env" => env, "apns_device_token" => apns_device_token, "ctx" => context}) do OpenTelemetry.Tracer.set_attribute(:request_id, conn.assigns.request_id) with {:apns_env, apns_env} <- {:apns_env, get_apns_env(env)}, {:encoding, ["aesgcm"]} <- {:encoding, get_req_header(conn, "content-encoding")}, {:body, {:ok, body, conn}} <- {:body, read_body(conn)}, {:salt, salt} when not is_nil(salt) <- get_salt(conn), {:key, key} when not is_nil(key) <- get_key(conn), {:forward, :ok} <- {:forward, Forwarder.forward(apns_env, apns_device_token, body, salt, key, context)} do send_resp(conn, 200, "ok") else {:apns_env, nil} -> Logger.error("Bad environment: #{env}") send_resp(conn, 400, "bad env") {:encoding, encoding} -> Logger.warning("Unexpected encoding: #{inspect(encoding)}") send_resp(conn, 400, "bad encoding") {:body, {:more, _, conn}} -> Logger.error("Didn't finish reading") send_resp(conn, 500, "failed to read body") {:body, {:error, reason}} -> Logger.error("Reading body: #{inspect(reason)}") send_resp(conn, 500, "failed to read body") {:salt, nil} -> Logger.warning("Missing salt") send_resp(conn, 400, "missing salt") {:key, nil} -> Logger.warning("Missing key") send_resp(conn, 400, "missing key") {:forward, {:error, :device_token_unregistered}} -> Logger.debug("APNS device token unregistered, removing registration") send_resp(conn, 400, "apns unregistered") {:forward, {:error, reason}} -> Logger.error("Sending notification: #{inspect(reason)}") send_resp(conn, 500, "failed to send") end end defp get_apns_env("development"), do: :development defp get_apns_env("production"), do: :production defp get_apns_env(_), do: nil defp get_salt(conn) do conn |> get_req_header("encryption") |> case do ["salt=" <> salt] -> {:salt, salt} _ -> {:salt, nil} end end defp get_key(conn) do conn |> get_req_header("crypto-key") |> case do [value] -> dh = value |> String.split(";") |> Enum.find_value(fn "dh=" <> val -> val _ -> false end) {:key, dh} _ -> {:key, nil} end end end