Current section
Files
Jump to
Current section
Files
lib/order.ex
defmodule AcmeEx.Order do
alias AcmeEx.{Account, Db}
def new(domains, account, token \\ nil), do: domains |> create(token) |> insert(account)
def fetch(client_key_or_id, order_id) do
client_key_or_id
|> account_id()
|> (&Db.fetch({:order, &1, order_id})).()
end
defp create(domains, token) do
%{
id: :erlang.unique_integer([:positive, :monotonic]),
status: :pending,
cert: nil,
domains: domains,
token: token || Base.url_encode64(:crypto.strong_rand_bytes(16), padding: false)
}
end
def update(client_key_or_id, order) do
client_key_or_id
|> account_id()
|> (&Db.store({:order, &1, order.id}, order)).()
|> case do
true -> {:ok, order}
_ -> {:error, "Unable to update order #{client_key_or_id}/#{order.id}"}
end
end
def domains(request) do
request.payload
|> Map.fetch!("identifiers")
|> Enum.filter(&(Map.fetch!(&1, "type") == "dns"))
|> Enum.map(&Map.fetch!(&1, "value"))
end
def identifiers(order), do: order.domains |> Enum.map(&%{type: "dns", value: &1})
def location(config, order, account) do
"#{config.site}/order/#{encode_path(order, account)}"
end
def authorization(config, order, account) do
"#{config.site}/authorizations/#{encode_path(order, account)}"
end
def finalize(config, order, account) do
"#{config.site}/finalize/#{encode_path(order, account)}"
end
def expires(duration \\ 3600, now \\ nil) do
(now || NaiveDateTime.utc_now())
|> NaiveDateTime.add(duration || 3600, :second)
|> DateTime.from_naive!("Etc/UTC")
|> DateTime.to_iso8601()
end
def encode_path(order, account), do: "#{account.id}/#{order.id}"
def decode_path(order_path) do
order_path
|> String.split("/")
|> Enum.map(&String.to_integer(&1))
|> (fn [account_id, order_id] ->
{
fetch(account_id, order_id) |> ok!,
%{id: account_id}
}
end).()
end
def to_challenge(config, order, account) do
%{
type: "http-01",
status: order.status,
url: "#{config.site}/challenge/http/#{encode_path(order, account)}",
token: order.token
}
end
def to_summary(config, order, account) do
%{
status: order.status,
identifier: %{type: "dns", value: "localhost"},
certificate: "#{config.site}/cert/#{encode_path(order, account)}"
}
end
defp insert(order, account) do
Db.create({:order, account.id, order.id}, order)
order
end
defp account_id(id) when is_integer(id), do: id
defp account_id(client_key) when is_binary(client_key) do
client_key
|> Account.fetch()
|> case do
{:ok, account} -> account.id
_ -> raise "Unable to locate account #{client_key}"
end
end
defp ok!({:ok, obj}), do: obj
end