1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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
|