diff options
Diffstat (limited to 'lib/lsg_web/controllers/irc_auth_sse_controller.ex')
-rw-r--r-- | lib/lsg_web/controllers/irc_auth_sse_controller.ex | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/lib/lsg_web/controllers/irc_auth_sse_controller.ex b/lib/lsg_web/controllers/irc_auth_sse_controller.ex new file mode 100644 index 0000000..c39a866 --- /dev/null +++ b/lib/lsg_web/controllers/irc_auth_sse_controller.ex @@ -0,0 +1,66 @@ +defmodule LSGWeb.IrcAuthSseController do + use LSGWeb, :controller + require Logger + + @ping_interval 20_000 + @expire_delay :timer.minutes(3) + + def sse(conn, params) do + perks = if uri = Map.get(params, "redirect_to") do + {:redirect, uri} + else + nil + end + token = String.downcase(EntropyString.random_string(65)) + conn + |> assign(:token, token) + |> assign(:perks, perks) + |> put_resp_header("X-Accel-Buffering", "no") + |> put_resp_header("content-type", "text/event-stream") + |> send_chunked(200) + |> subscribe() + |> send_sse_message("token", token) + |> sse_loop + end + + def subscribe(conn) do + :timer.send_interval(@ping_interval, {:event, :ping}) + :timer.send_after(@expire_delay, {:event, :expire}) + {:ok, _} = Registry.register(IRC.PubSub, "message:private", []) + conn + end + + def sse_loop(conn) do + {type, event, exit} = receive do + {:event, :ping} -> {"ping", "ping", false} + {:event, :expire} -> {"expire", "expire", true} + {:irc, :text, %{account: account, text: token} = m} -> + if String.downcase(String.trim(token)) == conn.assigns.token do + path = LSG.AuthToken.new_path(account.id, conn.assigns.perks) + m.replyfun.("ok!") + {"authenticated", path, true} + else + {nil, nil, false} + end + _ -> {nil, nil, false} + end + + conn = if type do + send_sse_message(conn, type, event) + else + conn + end + + if exit do + conn + else + sse_loop(conn) + end + end + + defp send_sse_message(conn, type, data) do + {:ok, conn} = chunk(conn, "event: #{type}\ndata: #{data}\n\n") + conn + end + +end |