summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantinos Kallas <konstantinos.kallas@hotmail.com>2017-07-17 10:42:09 +0300
committerKonstantinos Kallas <konstantinos.kallas@hotmail.com>2017-07-17 10:42:09 +0300
commitfa3108e6e2e1480915182ac6efb61a677092ef2b (patch)
treeb9a97804ece4a61361d4c4cb74e4b8ce08b34f1b
parentChange the persistent data structure from a record to a proplist (diff)
Save acquired certificates in persistent storage
-rw-r--r--include/ejabberd_acme.hrl4
-rw-r--r--src/ejabberd_acme.erl80
2 files changed, 71 insertions, 13 deletions
diff --git a/include/ejabberd_acme.hrl b/include/ejabberd_acme.hrl
index 0fea5bdf..cb711b27 100644
--- a/include/ejabberd_acme.hrl
+++ b/include/ejabberd_acme.hrl
@@ -11,10 +11,6 @@
key :: jose_jwk:key()
}).
--record(data_cert, {
- domain :: list(),
- pem :: binary()
- }).
diff --git a/src/ejabberd_acme.erl b/src/ejabberd_acme.erl
index 5d0608c9..527cef13 100644
--- a/src/ejabberd_acme.erl
+++ b/src/ejabberd_acme.erl
@@ -39,6 +39,7 @@ is_valid_account_opt("old-account") -> true;
is_valid_account_opt("new-account") -> true;
is_valid_account_opt(_) -> false.
+
%%
%% Get Certificate
%%
@@ -403,6 +404,10 @@ is_error(_) -> false.
data_empty() ->
[].
+%%
+%% Account
+%%
+
data_get_account(Data) ->
case lists:keyfind(account, 1, Data) of
{account, #data_acc{id = AccId, key = PrivateKey}} ->
@@ -415,6 +420,27 @@ data_set_account(Data, {AccId, PrivateKey}) ->
NewAcc = {account, #data_acc{id = AccId, key = PrivateKey}},
lists:keystore(account, 1, Data, NewAcc).
+%%
+%% Certificates
+%%
+
+data_get_certificates(Data) ->
+ case lists:keyfind(certs, 1, Data) of
+ {certs, Certs} ->
+ {ok, Certs};
+ false ->
+ {ok, []}
+ end.
+
+data_set_certificates(Data, NewCerts) ->
+ lists:keystore(certs, 1, Data, {certs, NewCerts}).
+
+%% ATM we preserve one certificate for each domain
+data_add_certificate(Data, {Domain, PemCert}) ->
+ {ok, Certs} = data_get_certificates(Data),
+ NewCerts = lists:keystore(Domain, 1, Certs, {Domain, PemCert}),
+ data_set_certificates(Data, NewCerts).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -475,6 +501,15 @@ read_account_persistent() ->
{ok, Data} = read_persistent(),
data_get_account(Data).
+read_certificates_persistent() ->
+ {ok, Data} = read_persistent(),
+ data_get_certificates(Data).
+
+add_certificate_persistent({Domain, PemCert}) ->
+ {ok, Data} = read_persistent(),
+ NewData = data_add_certificate(Data, {Domain, PemCert}),
+ ok = write_persistent(NewData).
+
save_certificate({error, _, _} = Error) ->
Error;
save_certificate({ok, DomainName, Cert}) ->
@@ -482,22 +517,30 @@ save_certificate({ok, DomainName, Cert}) ->
{ok, CertDir} = get_config_cert_dir(),
DomainString = bitstring_to_list(DomainName),
CertificateFile = filename:join([CertDir, DomainString ++ "_cert.pem"]),
- case file:write_file(CertificateFile, Cert) of
- ok ->
- {ok, DomainName, saved};
- {error, Reason} ->
- ?ERROR_MSG("Error: ~p saving certificate at file: ~p",
- [Reason, CertificateFile]),
- throw({error, DomainName, saving})
- end
+ %% TODO: At some point do the following using a Transaction so
+ %% that there is no certificate saved if it cannot be added in
+ %% certificate persistent storage
+ write_cert(CertificateFile, Cert, DomainName),
+ add_certificate_persistent({DomainName, Cert}),
+ {ok, DomainName, saved}
catch
throw:Throw ->
Throw;
E:R ->
- ?ERROR_MSG("unknown ~p:~p", [E,R]),
+ ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
{error, DomainName, saving}
end.
+write_cert(CertificateFile, Cert, DomainName) ->
+ case file:write_file(CertificateFile, Cert) of
+ ok ->
+ {ok, DomainName, saved};
+ {error, Reason} ->
+ ?ERROR_MSG("Error: ~p saving certificate at file: ~p",
+ [Reason, CertificateFile]),
+ throw({error, DomainName, saving})
+ end.
+
get_config_acme() ->
case ejabberd_config:get_option(acme, undefined) of
undefined ->
@@ -537,6 +580,25 @@ get_config_cert_dir() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
+%% Transaction Fun
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+transaction([{Fun, Rollback} | Rest]) ->
+ try
+ {ok, Result} = Fun(),
+ [Result | transaction(Rest)]
+ catch Type:Reason ->
+ Rollback(),
+ erlang:raise(Type, Reason, erlang:get_stacktrace())
+ end;
+transaction([Fun | Rest]) ->
+ % not every action require cleanup on error
+ transaction([{Fun, fun () -> ok end} | Rest]);
+transaction([]) -> [].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
%% Debugging Funcs -- They are only used for the development phase
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%