Current section

Files

Jump to
site_encrypt lib site_encrypt certification native.ex
Raw

lib/site_encrypt/certification/native.ex

defmodule SiteEncrypt.Certification.Native do
@moduledoc false
@behaviour SiteEncrypt.Certification.Job
alias SiteEncrypt.Acme.Client
alias SiteEncrypt.Certification.Job
@impl Job
def pems(config) do
{:ok,
Enum.into(
~w/privkey cert chain/a,
%{},
&{&1, File.read!(Path.join(domain_folder(config), "#{&1}.pem"))}
)}
catch
_, _ ->
:error
end
@impl Job
def certify(config, opts) do
case account_key(config) do
nil -> new_account(config, opts)
account_key -> new_cert(config, account_key, opts)
end
end
@impl Job
def full_challenge(_config, _challenge), do: raise("unknown challenge")
defp log(config, msg) do
SiteEncrypt.log(config, "#{msg} (CA #{URI.parse(SiteEncrypt.directory_url(config)).host})")
end
defp session_opts(opts), do: Keyword.take(opts, ~w/verify_server_cert/a)
defp new_account(config, opts) do
log(config, "Creating new account")
session = Client.new_account(config.id, session_opts(opts))
store_account_key!(config, session.account_key)
create_certificate(config, session)
end
defp new_cert(config, account_key, opts) do
session = Client.for_existing_account(config.id, account_key, session_opts(opts))
create_certificate(config, session)
end
defp create_certificate(config, session) do
log(config, "Ordering a new certificate for domain #{hd(config.domains)}")
{pems, _session} = Client.create_certificate(session, config.id)
store_pems!(config, pems)
log(config, "New certificate for domain #{hd(config.domains)} obtained")
end
defp account_key(config) do
File.read!(Path.join(ca_folder(config), "account_key.json"))
|> Jason.decode!()
|> JOSE.JWK.from_map()
catch
_, _ -> nil
end
defp store_account_key!(config, account_key) do
{_, map} = JOSE.JWK.to_map(account_key)
store_file!(Path.join(ca_folder(config), "account_key.json"), Jason.encode!(map))
end
defp store_pems!(config, pems) do
timestamp =
DateTime.utc_now()
|> DateTime.to_string()
|> String.replace(~r/[\- \:\.Z]/, "")
Enum.each(
pems,
fn {type, content} ->
store_file!(Path.join(domain_folder(config), "#{type}.pem"), content)
store_file!(
Path.join([domain_folder(config), "archive", timestamp, "#{type}.pem"]),
content
)
end
)
end
defp store_file!(path, content) do
File.mkdir_p(Path.dirname(path))
File.write!(path, content)
File.chmod!(path, 0o600)
end
defp domain_folder(config),
do: Path.join([ca_folder(config), "domains", hd(config.domains)])
defp ca_folder(config) do
Path.join([
config.db_folder,
"native",
"authorities",
case URI.parse(SiteEncrypt.directory_url(config)) do
%URI{host: host, port: 443} -> host
%URI{host: host, port: port} -> "#{host}_#{port}"
end
])
end
end