49 lines
1.4 KiB
Elixir
49 lines
1.4 KiB
Elixir
|
defmodule RecycledCloud.Accounts.Key do
|
||
|
use Ecto.Schema
|
||
|
import Ecto.Changeset
|
||
|
|
||
|
schema "keys" do
|
||
|
field :comment, :string
|
||
|
field :value, :string
|
||
|
field :fingerprint, :string
|
||
|
belongs_to :user, RecycledCloud.Accounts.User
|
||
|
|
||
|
timestamps()
|
||
|
end
|
||
|
|
||
|
def process_ssh_key(changeset, value_field, fingerprint_field, comment_field) do
|
||
|
raw_value = get_field(changeset, value_field)
|
||
|
comment = get_field(changeset, comment_field)
|
||
|
|
||
|
with {:is_valid, true} <- {:is_valid, changeset.valid?},
|
||
|
[{pk, attrs}] <- :public_key.ssh_decode(raw_value, :public_key) do
|
||
|
|
||
|
fingerprint = :public_key.ssh_hostkey_fingerprint(pk) |> List.to_string
|
||
|
changeset = put_change(changeset, fingerprint_field, fingerprint)
|
||
|
|
||
|
# Fetch comment from key, if not provided.
|
||
|
embedded_comment = attrs
|
||
|
|> Enum.into(%{})
|
||
|
|> Map.get(:comment)
|
||
|
|
||
|
case {comment, embedded_comment} do
|
||
|
{nil, nil} -> changeset
|
||
|
{nil, new_comment} ->
|
||
|
put_change(changeset, comment_field, List.to_string(new_comment))
|
||
|
{_, _} -> changeset
|
||
|
end
|
||
|
else
|
||
|
{:is_valid, false} -> changeset
|
||
|
_ -> add_error(changeset, value_field, "key is invalid")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
@doc false
|
||
|
def changeset(key, attrs) do
|
||
|
out = key
|
||
|
|> cast(attrs, [:comment, :value])
|
||
|
|> validate_required([:value])
|
||
|
|> process_ssh_key(:value, :fingerprint, :comment)
|
||
|
end
|
||
|
end
|