Initial commit on Forgejo
All checks were successful
CI and deploy / Test (push) Successful in 4m52s
CI and deploy / Deploy production (push) Successful in 23s

Fresh repository history for elektrine/tarakan hosted at
https://git.elektrine.com/elektrine/tarakan.
This commit is contained in:
Maxfield Luke 2026-07-29 04:43:40 -04:00
commit af6077b9c3
455 changed files with 78366 additions and 0 deletions

View file

@ -0,0 +1,189 @@
defmodule TarakanWeb.ClientAuthorizationLive do
use TarakanWeb, :live_view
alias Tarakan.Accounts.ClientAuthorizations
@impl true
def mount(%{"user_code" => user_code}, _session, socket) do
actor_key = socket.assigns.current_scope.account.id
case ClientAuthorizations.get_for_browser(user_code, actor_key) do
{:ok, authorization} ->
{:ok,
socket
|> assign(:authorization, authorization)
|> assign(
:display_code,
ClientAuthorizations.display_user_code(authorization.user_code)
)
|> assign(:page_title, "Authorize Tarakan Client")}
# Throttled and missing look the same on purpose: telling a grinder which
# of its guesses were merely rate limited would hand back the oracle.
{:error, _reason} ->
{:ok,
socket
|> assign(:authorization, nil)
|> assign(:display_code, user_code)
|> assign(:page_title, "Login request expired")}
end
end
@impl true
def handle_event(action, _params, %{assigns: %{authorization: nil}} = socket)
when action in ["approve", "deny"] do
{:noreply, put_flash(socket, :error, "This login request has expired or was already used.")}
end
def handle_event("approve", _params, socket) do
account = socket.assigns.current_scope.account
case ClientAuthorizations.approve(socket.assigns.authorization, account) do
{:ok, authorization} ->
{:noreply,
socket
|> assign(:authorization, authorization)
|> put_flash(:info, "Connected. You can go back to the terminal.")}
{:error, _reason} ->
{:noreply,
socket
|> assign(:authorization, nil)
|> put_flash(:error, "This login request expired or was already used.")}
end
end
def handle_event("deny", _params, socket) do
account = socket.assigns.current_scope.account
case ClientAuthorizations.deny(socket.assigns.authorization, account) do
{:ok, authorization} ->
{:noreply,
socket
|> assign(:authorization, authorization)
|> put_flash(:info, "Denied.")}
{:error, _reason} ->
{:noreply, assign(socket, :authorization, nil)}
end
end
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope} current_path={assigns[:current_path]}>
<Layouts.page id="client-authorization-page" width={:compact}>
<section class={[
"border-2 border-strong bg-panel p-6 shadow-[8px_8px_0_0_var(--color-rule)] sm:p-8"
]}>
<div class={["flex items-start gap-4"]}>
<div class={[
"flex size-11 shrink-0 items-center justify-center bg-signal text-ground"
]}>
<.icon name="hero-command-line" class={["size-6"]} />
</div>
<div class={["min-w-0"]}>
<h1 class={[
"font-display text-2xl font-medium uppercase tracking-[0.02em] text-ink"
]}>
Connect your terminal
</h1>
<p class={["mt-2 text-sm leading-6 text-ink-muted"]}>
Approving lets the client claim jobs as @{@current_scope.account.handle}.
</p>
</div>
</div>
<%= cond do %>
<% is_nil(@authorization) -> %>
<div id="client-authorization-expired" class={["mt-8 border-2 border-rule p-5"]}>
<p class={["text-sm text-ink"]}>
That code is invalid or expired. Run <code class="font-mono">tarakan login</code>
again.
</p>
</div>
<% @authorization.status == "approved" -> %>
<div
id="client-authorization-approved"
class={["mt-8 border-2 border-phosphor bg-ground p-5"]}
>
<p class={["text-sm font-semibold text-ink"]}>Connected.</p>
<p class={["mt-1 text-sm text-ink-muted"]}>Back to your terminal.</p>
</div>
<% @authorization.status == "denied" -> %>
<div id="client-authorization-denied" class={["mt-8 border-2 border-rule p-5"]}>
<p class={["text-sm text-ink"]}>Denied. Nothing was granted.</p>
</div>
<% true -> %>
<div id="client-authorization-pending" class={["mt-8"]}>
<p class={["text-xs font-semibold text-ink-muted"]}>
Code
</p>
<%!-- Deliberately outside the two-token tracking scale (0.12em
labels / 0.02em display): this is a code the user transcribes
by hand, and the wide gaps keep characters from running together. --%>
<div
id="client-authorization-code"
class={[
"mt-2 border-2 border-strong bg-ground px-4 py-3 font-mono text-2xl tracking-[0.2em] text-ink sm:text-3xl"
]}
>
{@display_code}
</div>
<%!-- The name comes from whoever started the login, not from
Tarakan, so it is attributed rather than asserted: a
request that calls itself something official must not read
as though this page vouches for it. --%>
<p class={["mt-5 text-xs font-semibold text-ink-muted"]}>
Calls itself
</p>
<p
id="client-authorization-client-name"
class={[
"mt-1 border-2 border-rule bg-ground px-3 py-2 font-mono text-sm text-ink"
]}
>
{@authorization.client_name}
</p>
<p class={["mt-4 text-sm text-ink-muted"]}>
Approving lets it claim jobs and submit reviews as
<span class="font-semibold text-ink">@{@current_scope.account.handle}</span>
for about 7 days. Revoke anytime in settings.
</p>
<p class={["mt-2 text-sm text-ink-muted"]}>
Only approve this if you just ran
<code class="font-mono text-ink">tarakan login</code>
yourself and the code above matches your terminal. Nobody at Tarakan will
ever ask you for it.
</p>
<div class={["mt-6 grid gap-3 sm:grid-cols-2"]}>
<button
id="client-authorization-deny-button"
phx-click="deny"
class={[
"flex h-12 items-center justify-center border border-strong px-4 font-display text-sm uppercase tracking-[0.12em] text-ink transition hover:bg-ground"
]}
>
Deny
</button>
<button
id="client-authorization-approve-button"
phx-click="approve"
class={[
"clip-notch flex h-12 items-center justify-center bg-btn px-4 font-display text-sm uppercase tracking-[0.12em] text-btn-fg transition hover:opacity-90"
]}
>
Approve
</button>
</div>
</div>
<% end %>
</section>
</Layouts.page>
</Layouts.app>
"""
end
end