summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorhref <href@random.sh>2021-09-07 05:28:02 +0200
committerhref <href@random.sh>2021-09-07 05:28:02 +0200
commitcf7b21afa87ca5202bd626d26a60adab1e9131a1 (patch)
tree245cbb332e9ab63a2b84e4168e0ce750dc1e7ae9 /lib
parentuser_track: fix find_by_account/2 (diff)
web: openid & various fixes
Diffstat (limited to '')
-rw-r--r--lib/lsg_web.ex6
-rw-r--r--lib/lsg_web/context_plug.ex12
-rw-r--r--lib/lsg_web/controllers/irc_controller.ex7
-rw-r--r--lib/lsg_web/controllers/open_id_controller.ex64
-rw-r--r--lib/lsg_web/live/chat_live.ex7
-rw-r--r--lib/lsg_web/router.ex6
-rw-r--r--lib/lsg_web/templates/alcoolog/auth.html.eex12
-rw-r--r--lib/lsg_web/templates/irc/index.html.eex15
-rw-r--r--lib/lsg_web/templates/layout/app.html.eex4
-rw-r--r--lib/lsg_web/templates/open_id/error.html.eex3
-rw-r--r--lib/lsg_web/templates/page/user.html.eex5
-rw-r--r--lib/lsg_web/views/open_id_view.ex4
12 files changed, 124 insertions, 21 deletions
diff --git a/lib/lsg_web.ex b/lib/lsg_web.ex
index eb0cdc5..3d9ab9a 100644
--- a/lib/lsg_web.ex
+++ b/lib/lsg_web.ex
@@ -29,12 +29,15 @@ defmodule LSGWeb do
chan
end
+ def format_chan(chan = "!"<>_), do: chan
+
def reformat_chan("♯") do
"#"
end
def reformat_chan("♯♯") do
"##"
end
+ def reformat_chan(chan = "!"<>_), do: chan
def reformat_chan(chan) do
"#"<>chan
@@ -46,6 +49,7 @@ defmodule LSGWeb do
import Plug.Conn
import LSGWeb.Router.Helpers
import LSGWeb.Gettext
+ alias LSGWeb.Router.Helpers, as: Routes
end
end
@@ -65,6 +69,8 @@ defmodule LSGWeb do
import LSGWeb.Gettext
import Phoenix.LiveView.Helpers
+
+ alias LSGWeb.Router.Helpers, as: Routes
end
end
diff --git a/lib/lsg_web/context_plug.ex b/lib/lsg_web/context_plug.ex
index 7896ace..29eab28 100644
--- a/lib/lsg_web/context_plug.ex
+++ b/lib/lsg_web/context_plug.ex
@@ -6,9 +6,16 @@ defmodule LSGWeb.ContextPlug do
opts || []
end
+ def get_account(conn) do
+ cond do
+ get_session(conn, :account) -> get_session(conn, :account)
+ get_session(conn, :oidc_id) -> if account = IRC.Account.find_meta_account("identity-id", get_session(conn, :oidc_id)), do: account.id
+ end
+ end
+
def call(conn, opts) do
account = with \
- {:account, account_id} when is_binary(account_id) <- {:account, get_session(conn, :account)},
+ {:account, account_id} when is_binary(account_id) <- {:account, get_account(conn)},
{:account, account} when not is_nil(account) <- {:account, IRC.Account.get(account_id)}
do
account
@@ -19,6 +26,8 @@ defmodule LSGWeb.ContextPlug do
network = Map.get(conn.params, "network")
network = if network == "-", do: nil, else: network
+ oidc_account = IRC.Account.find_meta_account("identity-id", get_session(conn, :oidc_id))
+
conns = IRC.Connection.get_network(network)
chan = if c = Map.get(conn.params, "chan") do
LSGWeb.reformat_chan(c)
@@ -74,6 +83,7 @@ defmodule LSGWeb.ContextPlug do
|> assign(:chan, chan)
|> assign(:bot, bot)
|> assign(:account, account)
+ |> assign(:oidc_account, oidc_account)
|> assign(:memberships, memberships)
end
end
diff --git a/lib/lsg_web/controllers/irc_controller.ex b/lib/lsg_web/controllers/irc_controller.ex
index 32007c2..d518481 100644
--- a/lib/lsg_web/controllers/irc_controller.ex
+++ b/lib/lsg_web/controllers/irc_controller.ex
@@ -5,7 +5,7 @@ defmodule LSGWeb.IrcController do
def index(conn, params) do
network = Map.get(params, "network")
- channel = if c = Map.get(params, "channel"), do: LSGWeb.reformat_chan(c)
+ channel = if c = Map.get(params, "chan"), do: LSGWeb.reformat_chan(c)
commands = for mod <- Enum.uniq([IRC.Account.AccountPlugin] ++ IRC.Plugin.enabled()) do
if is_atom(mod) do
identifier = Module.split(mod) |> List.last |> String.replace("Plugin", "") |> Macro.underscore
@@ -15,8 +15,9 @@ defmodule LSGWeb.IrcController do
|> Enum.filter(& &1)
|> Enum.filter(fn({_, doc}) -> doc end)
members = cond do
- network -> IRC.Membership.expanded_members_or_friends(conn.assigns.account, network, channel)
- true -> IRC.Membership.of_account(conn.assigns.account)
+ network && channel -> Enum.map(IRC.UserTrack.channel(network, channel), fn(tuple) -> IRC.UserTrack.User.from_tuple(tuple) end)
+ true ->
+ IRC.Membership.of_account(conn.assigns.account)
end
render conn, "index.html", network: network, commands: commands, channel: channel, members: members
end
diff --git a/lib/lsg_web/controllers/open_id_controller.ex b/lib/lsg_web/controllers/open_id_controller.ex
new file mode 100644
index 0000000..d5af318
--- /dev/null
+++ b/lib/lsg_web/controllers/open_id_controller.ex
@@ -0,0 +1,64 @@
+defmodule LSGWeb.OpenIdController do
+ use LSGWeb, :controller
+ plug LSGWeb.ContextPlug, restrict: :public
+ require Logger
+
+ def login(conn, _) do
+ url = OAuth2.Client.authorize_url!(new_client(), scope: "openid", state: Base.url_encode64(:crypto.strong_rand_bytes(32), padding: false))
+ redirect(conn, external: url)
+ end
+
+ def callback(conn, %{"error" => error_code, "error_description" => error}) do
+ Logger.warn("OpenId error: #{error_code} #{error}")
+ render(conn, "error.html", error: error)
+ end
+
+ def callback(conn, %{"code" => code, "state" => state}) do
+ with \
+ client = %{token: %OAuth2.AccessToken{access_token: json}} = OAuth2.Client.get_token!(new_client(), state: state, code: code),
+ {:ok, %{"access_token" => token}} <- Jason.decode(json),
+ client = %OAuth2.Client{client | token: %OAuth2.AccessToken{access_token: token}},
+ {:ok, %OAuth2.Response{body: body}} <- OAuth2.Client.get(client, "/userinfo"),
+ {:ok, %{"sub" => id, "preferred_username" => username}} <- Jason.decode(body)
+ do
+ if account = conn.assigns.account do
+ if !IRC.Account.get_meta(account, "identity-id") do # XXX: And oidc id not linked yet
+ IRC.Account.put_meta(account, "identity-id", id)
+ end
+ IRC.Account.put_meta(account, "identity-username", username)
+ conn
+ else
+ conn
+ end
+
+ conn
+ |> put_session(:oidc_id, id)
+ |> put_flash(:info, "Logged in!")
+ |> redirect(to: Routes.path(conn, "/"))
+ else
+ {:error, %OAuth2.Response{status_code: 401}} ->
+ Logger.error("OpenID: Unauthorized token")
+ render(conn, "error.html", error: "The token is invalid.")
+ {:error, %OAuth2.Error{reason: reason}} ->
+ Logger.error("Error: #{inspect reason}")
+ render(conn, "error.html", error: reason)
+ end
+ end
+
+ def callback(conn, _params) do
+ render(conn, "error.html", error: "Unspecified error.")
+ end
+
+ defp new_client() do
+ config = Application.get_env(:lsg, :oidc)
+ OAuth2.Client.new([
+ strategy: OAuth2.Strategy.AuthCode,
+ client_id: config[:client_id],
+ client_secret: config[:client_secret],
+ site: config[:base_url],
+ authorize_url: config[:authorize_url],
+ token_url: config[:token_url],
+ redirect_uri: Routes.open_id_url(LSGWeb.Endpoint, :callback)
+ ])
+ end
+end
diff --git a/lib/lsg_web/live/chat_live.ex b/lib/lsg_web/live/chat_live.ex
index d736d72..e7a44db 100644
--- a/lib/lsg_web/live/chat_live.ex
+++ b/lib/lsg_web/live/chat_live.ex
@@ -22,7 +22,10 @@ defmodule LSGWeb.ChatLive do
Map.put(acc, id, user)
end)
- {backlog, _} = LSG.IRC.BufferPlugin.select_buffer(connection.network, chan)
+ backlog = case LSG.IRC.BufferPlugin.select_buffer(connection.network, chan) do
+ {backlog, _} -> Enum.reverse(backlog)
+ _ -> []
+ end
socket = socket
|> assign(:connection_id, connection.id)
@@ -31,7 +34,7 @@ defmodule LSGWeb.ChatLive do
|> assign(:title, "live")
|> assign(:channel, chan)
|> assign(:account_id, account.id)
- |> assign(:backlog, Enum.reverse(backlog))
+ |> assign(:backlog, backlog)
|> assign(:users, users)
|> assign(:counter, 0)
diff --git a/lib/lsg_web/router.ex b/lib/lsg_web/router.ex
index e872cef..eba71dc 100644
--- a/lib/lsg_web/router.ex
+++ b/lib/lsg_web/router.ex
@@ -32,10 +32,15 @@ defmodule LSGWeb.Router do
get "/", PageController, :index
get "/login/irc/:token", PageController, :token, as: :login
+ get "/login/oidc", OpenIdController, :login
+ get "/login/oidc/callback", OpenIdController, :callback
+
get "/api/untappd/callback", UntappdController, :callback, as: :untappd_callback
+
get "/-", IrcController, :index
get "/-/txt", IrcController, :txt
get "/-/txt/:name", IrcController, :txt
+
get "/-/alcoolog", AlcoologController, :index
get "/-/alcoolog/~/:account_name", AlcoologController, :index
get "/:network", NetworkController, :index
@@ -48,6 +53,7 @@ defmodule LSGWeb.Router do
get "/:network/:chan/alcoolog", AlcoologController, :index
get "/:network/:chan/alcoolog/gls.json", AlcoologController, :index_gls_json
put "/api/alcoolog/minisync/:user_id/meta/:key", AlcoologController, :minisync_put_meta
+
get "/:network/:chan", IrcController, :index
live "/:network/:chan/live", ChatLive
get "/:network/:chan/txt", IrcController, :txt
diff --git a/lib/lsg_web/templates/alcoolog/auth.html.eex b/lib/lsg_web/templates/alcoolog/auth.html.eex
index af6db53..6e5cedc 100644
--- a/lib/lsg_web/templates/alcoolog/auth.html.eex
+++ b/lib/lsg_web/templates/alcoolog/auth.html.eex
@@ -1,6 +1,11 @@
-<h1>authentication</h1>
+<div class="grid grid-cols-2">
+ <h1 class="text-2xl font-bold">authentication</h1>
+ <div class="text-right">
+ <%= link("connect using random.sh", to: "/login/oidc", class: "inline-block font-medium underline") %>
+ </div>
+</div>
-<div id="authenticator">
+<div id="authenticator" class="mt-12 h-32 place-self-end justify-self-start">
<p>
<%= if @bot, do: "Send this to #{@bot} on #{@network}:", else: "Find your bot nickname and send:" %><br /><br />
<strong>/msg <%= @bot || "the-bot-nickname" %> web</strong>
@@ -12,7 +17,7 @@
<script type="text/javascript">
var authSse = new EventSource("/api/irc-auth.sse?redirect_to=" + window.location.pathname);
authSse.addEventListener("token", function(event) {
- html = "<%= if @bot, do: "Send this to #{@bot} on #{@network}:", else: "Find your bot nickname and send:" %><br /><br /><strong>/msg <%= @bot || "the-bot-nickname" %> "+event.data+"</strong>";
+ html = "<%= if @bot, do: "Send this to #{@bot} on #{@network}:", else: "Find your bot nickname and send:" %><br /><br /><strong class='text-xl font-mono ml-12'>/msg <%= @bot || "<the-bot-nickname>" %> "+event.data+"</strong>";
elem = document.getElementById("authenticator");
elem.innerHTML = html;
});
@@ -36,4 +41,3 @@
};
</script>
-
diff --git a/lib/lsg_web/templates/irc/index.html.eex b/lib/lsg_web/templates/irc/index.html.eex
index f20f444..52372b5 100644
--- a/lib/lsg_web/templates/irc/index.html.eex
+++ b/lib/lsg_web/templates/irc/index.html.eex
@@ -1,22 +1,21 @@
<div class="hidden sm:block">
- <nav class="flex flex-wrap content-center">
- <%= link("live", to: LSGWeb.Router.Helpers.live_path(LSGWeb.Endpoint, LSGWeb.ChatLive, @network, LSGWeb.format_chan(@chan)), class: "px-3 py-2 font-medium text-sm leading-5 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:text-indigo-600 focus:bg-indigo-50") %>
+ <nav class="flex flex-wrap space-x-4">
+ <%= link("live", to: LSGWeb.Router.Helpers.live_path(LSGWeb.Endpoint, LSGWeb.ChatLive, @network, LSGWeb.format_chan(@chan)), class: "py-4 font-medium leading-5 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:text-indigo-600 focus:bg-indigo-50", 'data-turbo': false) %>
<% list = for {identifier, _} <- @commands do %>
<% name = String.replace(identifier, "_", " ") %>
- <%= link(name, to: "##{identifier}", class: "px-3 py-2 font-medium text-sm leading-5 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:text-indigo-600 focus:bg-indigo-50") %>
+ <%= link(name, to: "##{identifier}", class: "py-4 font-medium leading-5 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:text-indigo-600 focus:bg-indigo-50") %>
<% end %>
<%= list %>
</nav>
</div>
<%= if @members != [] do %>
-<% users = for {_acc, user, nick} <- @members, do: if(user, do: nick, else: content_tag(:i, nick)) %>
-<%= for u <- Enum.intersperse(users, ", ") do %>
- <%= u %>
-<% end %>
+ <ul class="flex flew-wrap space-x-4 mt-12">
+ <%= for user <- @members do %><li><%= user.nick %></li><% end %>
+ </ul>
<% end %>
-<div class="irchelps space-y-6">
+<div class="irchelps space-y-6 mt-12">
<%= for {identifier, help} <- @commands do %>
<%= if help do %>
<div class="bg-white border-b border-gray-200" id="<%= identifier %>">
diff --git a/lib/lsg_web/templates/layout/app.html.eex b/lib/lsg_web/templates/layout/app.html.eex
index bca1555..b918ca5 100644
--- a/lib/lsg_web/templates/layout/app.html.eex
+++ b/lib/lsg_web/templates/layout/app.html.eex
@@ -107,8 +107,8 @@
<h1 class="text-3xl leading-9 font-bold text-white">
<%= if n = @conn.assigns[:network] do %><a href="/<%= n %>"><%= n %></a> &rsaquo; <% end %>
<%= if c = @conn.assigns[:chan] do %><a href="/<%= @conn.assigns.network %>/<%= LSGWeb.format_chan(c) %>"><%= c %></a> &rsaquo; <% end %>
- <%= for({name, href} <- @conn.assigns[:breadcrumbs]||[], do: [link(name, to: href), raw(" &rsaquo; ")]) %>
- <%= @conn.assigns[:title] || @conn.assigns[:chan] || @conn.assigns[:network] %>
+ <%= for({name, href} <- Enum.uniq(@conn.assigns[:breadcrumbs]||[]), do: [link(name, to: href), raw(" &rsaquo; ")]) %>
+ <%= @conn.assigns[:title] %>
</h1>
</div>
</header>
diff --git a/lib/lsg_web/templates/open_id/error.html.eex b/lib/lsg_web/templates/open_id/error.html.eex
new file mode 100644
index 0000000..d1b35b9
--- /dev/null
+++ b/lib/lsg_web/templates/open_id/error.html.eex
@@ -0,0 +1,3 @@
+<h1 class="text-xl font-bold text-red-800">OpenID authentication error</h1>
+
+<p class="mt-12 text-base prose"><%= @error %></p>
diff --git a/lib/lsg_web/templates/page/user.html.eex b/lib/lsg_web/templates/page/user.html.eex
index 56fc485..6eeb39d 100644
--- a/lib/lsg_web/templates/page/user.html.eex
+++ b/lib/lsg_web/templates/page/user.html.eex
@@ -1,6 +1,9 @@
<div class="prose prose-lg">
<ul>
- <li><%= link("Help", to: "/-") %></li>
+ <li><%= link("Help", to: "/-") %></li>
+ <%= unless List.keyfind(@metas, "identity-id", 0) do %>
+ <li><%= link("Connect with random.sh", to: Routes.open_id_path(@conn, :login)) %></li>
+ <% end %>
</ul>
<h2>channels</h2>
diff --git a/lib/lsg_web/views/open_id_view.ex b/lib/lsg_web/views/open_id_view.ex
new file mode 100644
index 0000000..64d4430
--- /dev/null
+++ b/lib/lsg_web/views/open_id_view.ex
@@ -0,0 +1,4 @@
+defmodule LSGWeb.OpenIdView do
+ use LSGWeb, :view
+
+end