mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-11 14:06:20 +08:00
Add secret key to personal hub edit form (#1776)
Co-authored-by: José Valim <jose.valim@dashbit.co>
This commit is contained in:
parent
52f94a09e4
commit
9712554c14
3 changed files with 112 additions and 40 deletions
|
@ -6,6 +6,8 @@ defmodule Livebook.Hubs.Personal do
|
|||
|
||||
alias Livebook.Hubs
|
||||
|
||||
@secret_key_size 64
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
id: String.t() | nil,
|
||||
hub_name: String.t() | nil,
|
||||
|
@ -65,6 +67,12 @@ defmodule Livebook.Hubs.Personal do
|
|||
personal
|
||||
|> cast(attrs, @fields)
|
||||
|> validate_required(@fields)
|
||||
|> validate_change(:secret_key, fn :secret_key, secret_key ->
|
||||
case Base.url_decode64(secret_key, padding: false) do
|
||||
{:ok, binary} when byte_size(binary) == @secret_key_size -> []
|
||||
_ -> [secret_key: "must be #{@secret_key_size} bytes in Base 64 URL alphabet"]
|
||||
end
|
||||
end)
|
||||
|> put_change(:id, id())
|
||||
end
|
||||
|
||||
|
@ -73,7 +81,7 @@ defmodule Livebook.Hubs.Personal do
|
|||
"""
|
||||
@spec generate_secret_key() :: String.t()
|
||||
def generate_secret_key() do
|
||||
:crypto.strong_rand_bytes(64) |> Base.url_encode64(padding: false)
|
||||
:crypto.strong_rand_bytes(@secret_key_size) |> Base.url_encode64(padding: false)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ defmodule LivebookWeb.FormComponents do
|
|||
name={@name}
|
||||
id={@id || @name}
|
||||
value={Phoenix.HTML.Form.normalize_value("text", @value)}
|
||||
class="input"
|
||||
class="input pr-8"
|
||||
{@rest}
|
||||
/>
|
||||
</.with_password_toggle>
|
||||
|
@ -310,21 +310,11 @@ defmodule LivebookWeb.FormComponents do
|
|||
|
||||
~H"""
|
||||
<.field_wrapper id={@id} name={@name} label={@label} errors={@errors}>
|
||||
<div class="flex border-[1px] bg-gray-50 rounded-lg space-x-4 items-center">
|
||||
<div
|
||||
id={"#{@id}-picker"}
|
||||
class="grid grid-cols-1 md:grid-cols-3 w-full"
|
||||
phx-hook="EmojiPicker"
|
||||
>
|
||||
<div class="place-content-start">
|
||||
<div class="p-1 pl-3">
|
||||
<div class="flex border bg-gray-50 rounded-lg space-x-4 items-center">
|
||||
<div id={"#{@id}-picker"} class="flex w-full" phx-hook="EmojiPicker">
|
||||
<div class="grow p-1 pl-3">
|
||||
<span id={"#{@id}-preview"} data-emoji-preview><%= @value %></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div />
|
||||
|
||||
<div class="flex items-center place-content-end">
|
||||
<button
|
||||
id={"#{@id}-button"}
|
||||
type="button"
|
||||
|
@ -333,7 +323,6 @@ defmodule LivebookWeb.FormComponents do
|
|||
>
|
||||
<.remix_icon icon="emotion-line" class="text-xl" />
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type="hidden"
|
||||
name={@name}
|
||||
|
@ -434,7 +423,7 @@ defmodule LivebookWeb.FormComponents do
|
|||
|
||||
def error(assigns) do
|
||||
~H"""
|
||||
<p class="text-red-600 text-sm hidden phx-form-error:block">
|
||||
<p class="mt-0.5 text-red-600 text-sm hidden phx-form-error:block">
|
||||
<%= render_slot(@inner_block) %>
|
||||
</p>
|
||||
"""
|
||||
|
|
|
@ -17,7 +17,7 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
|
|||
{:ok,
|
||||
socket
|
||||
|> assign(assigns)
|
||||
|> assign(changeset: changeset, secret_value: secret_value)}
|
||||
|> assign(changeset: changeset, stamp_changeset: changeset, secret_value: secret_value)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
@ -58,7 +58,7 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
|
|||
phx-disable-with="Updating..."
|
||||
disable={not @changeset.valid?}
|
||||
>
|
||||
Update Hub
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</.form>
|
||||
|
@ -76,6 +76,61 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
|
|||
target={@myself}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col space-y-4">
|
||||
<h2 class="text-xl text-gray-800 font-medium pb-2 border-b border-gray-200">
|
||||
Stamping
|
||||
</h2>
|
||||
|
||||
<p class="text-gray-700">
|
||||
Notebooks may be stamped using your <span class="font-medium text-gray-800">secret key</span>.
|
||||
A stamp allows to securely store information such as the names of the secrets that you granted access to.
|
||||
You must not share your secret key with others. But you may copy the secret key between
|
||||
different machines you own.
|
||||
</p>
|
||||
<p class="text-gray-700">
|
||||
If you change the <span class="font-medium text-gray-800">secret key</span>, you will need
|
||||
to grant access to secrets once again in previously stamped notebooks.
|
||||
</p>
|
||||
|
||||
<.form
|
||||
:let={f}
|
||||
id={"#{@id}-stamp"}
|
||||
class="flex flex-col mt-4 space-y-4"
|
||||
for={@stamp_changeset}
|
||||
phx-submit="stamp_save"
|
||||
phx-change="stamp_validate"
|
||||
phx-target={@myself}
|
||||
>
|
||||
<div class="flex space-x-2">
|
||||
<div class="grow">
|
||||
<.password_field field={f[:secret_key]} label="Secret key" />
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<span class="tooltip top" data-tooltip="Generate">
|
||||
<button
|
||||
class="button-base button-outlined-gray button-square-icon"
|
||||
type="button"
|
||||
phx-click="generate_secret_key"
|
||||
phx-target={@myself}
|
||||
>
|
||||
<.remix_icon icon="refresh-line" class="text-xl" />
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="button-base button-blue"
|
||||
type="submit"
|
||||
phx-disable-with="Updating..."
|
||||
disable={not @stamp_changeset.valid?}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</.form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<.modal
|
||||
|
@ -183,20 +238,24 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
|
|||
|
||||
@impl true
|
||||
def handle_event("save", %{"personal" => params}, socket) do
|
||||
case Personal.update_hub(socket.assigns.hub, params) do
|
||||
{:ok, hub} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:success, "Hub updated successfully")
|
||||
|> push_navigate(to: ~p"/hub/#{hub.id}")}
|
||||
|
||||
{:error, changeset} ->
|
||||
{:noreply, assign(socket, changeset: changeset)}
|
||||
end
|
||||
{:noreply, save(params, :changeset, socket)}
|
||||
end
|
||||
|
||||
def handle_event("validate", %{"personal" => attrs}, socket) do
|
||||
{:noreply, assign(socket, changeset: Personal.validate_hub(socket.assigns.hub, attrs))}
|
||||
def handle_event("validate", %{"personal" => params}, socket) do
|
||||
{:noreply, validate(params, :changeset, socket)}
|
||||
end
|
||||
|
||||
def handle_event("stamp_save", %{"personal" => params}, socket) do
|
||||
{:noreply, save(params, :stamp_changeset, socket)}
|
||||
end
|
||||
|
||||
def handle_event("stamp_validate", %{"personal" => params}, socket) do
|
||||
{:noreply, validate(params, :stamp_changeset, socket)}
|
||||
end
|
||||
|
||||
def handle_event("generate_secret_key", %{}, socket) do
|
||||
params = %{"secret_key" => Personal.generate_secret_key()}
|
||||
{:noreply, validate(params, :stamp_changeset, socket)}
|
||||
end
|
||||
|
||||
def handle_event("delete_hub_secret", attrs, socket) do
|
||||
|
@ -205,4 +264,20 @@ defmodule LivebookWeb.Hub.Edit.PersonalComponent do
|
|||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp save(params, changeset_name, socket) do
|
||||
case Personal.update_hub(socket.assigns.hub, params) do
|
||||
{:ok, hub} ->
|
||||
socket
|
||||
|> put_flash(:success, "Hub updated successfully")
|
||||
|> push_navigate(to: ~p"/hub/#{hub.id}")
|
||||
|
||||
{:error, changeset} ->
|
||||
assign(socket, changeset_name, changeset)
|
||||
end
|
||||
end
|
||||
|
||||
defp validate(params, changeset_name, socket) do
|
||||
assign(socket, changeset_name, Personal.validate_hub(socket.assigns.hub, params))
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue