defmodule Meta.Accounts.Key do use Ecto.Schema import Ecto.Changeset schema "keys" do field :comment, :string field :value, :string field :fingerprint, :string belongs_to :user, Meta.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 key |> cast(attrs, [:comment, :value]) |> validate_required([:value]) |> process_ssh_key(:value, :fingerprint, :comment) end end