25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-02 16:37:52 +01:00

Make Stylistic Changes in order to conform to guidelines:

1. Remove trailing whitespace
2. Remove Macros
3. Handle all erroneous response codes the same way
4. Add specs
Also don't return nonces anymore when the http response is negative.
This commit is contained in:
Konstantinos Kallas 2017-06-09 18:53:54 +03:00
parent 53d47483c8
commit 167edacb5f

View File

@ -1,7 +1,7 @@
-module (ejabberd_acme). -module (ejabberd_acme).
-export([ scenario/3 -export([ scenario/3
, scenario0/0 , scenario0/1
, directory/1 , directory/1
, get_account/3 , get_account/3
, new_account/4 , new_account/4
@ -14,12 +14,15 @@
-include_lib("public_key/include/public_key.hrl"). -include_lib("public_key/include/public_key.hrl").
-define(REQUEST_TIMEOUT, 5000). % 5 seconds. -define(REQUEST_TIMEOUT, 5000). % 5 seconds.
-define(DIRURL, "directory").
-define(REGURL, "/acme/reg/").
-define(DEFAULT_KEY_FILE, "private_key_temporary").
-type nonce() :: string().
-type url() :: string().
-type proplist() :: [{_, _}].
-type jws() :: map().
-spec directory(url()) ->
{ok, map(), nonce()} | {error, _}.
directory(DirURL) -> directory(DirURL) ->
Options = [], Options = [],
HttpOptions = [{timeout, ?REQUEST_TIMEOUT}], HttpOptions = [{timeout, ?REQUEST_TIMEOUT}],
@ -34,21 +37,22 @@ directory(DirURL) ->
%% Return Map of Directories %% Return Map of Directories
NewDirs = maps:from_list(StrDirectories), NewDirs = maps:from_list(StrDirectories),
{ok, NewDirs, Nonce}; {ok, NewDirs, Nonce};
{ok, {{_, Code, _}, Head, _Body}} -> {ok, {{_, Code, _}, _Head, _Body}} ->
?ERROR_MSG("Got unexpected status code from <~s>: ~B", ?ERROR_MSG("Got unexpected status code from <~s>: ~B",
[DirURL, Code]), [DirURL, Code]),
Nonce = get_nonce(Head), {error, unexpected_code};
{error, unexpected_code, Nonce};
{error, Reason} -> {error, Reason} ->
?ERROR_MSG("Error requesting directory from <~s>: ~p", ?ERROR_MSG("Error requesting directory from <~s>: ~p",
[DirURL, Reason]), [DirURL, Reason]),
{error, Reason} {error, Reason}
end. end.
-spec new_account(url(), jose_jwk:key(), proplist(), nonce()) ->
{ok, {url(), proplist()}, nonce()} | {error, _}.
new_account(NewAccURl, PrivateKey, Req, Nonce) -> new_account(NewAccURl, PrivateKey, Req, Nonce) ->
%% Make the request body %% Make the request body
ReqBody = jiffy:encode({[{ <<"resource">>, <<"new-reg">>}] ++ Req}), ReqBody = jiffy:encode({[{ <<"resource">>, <<"new-reg">>}] ++ Req}),
{_, SignedBody} = sign_json_jose(PrivateKey, ReqBody, NewAccURl, Nonce), {_, SignedBody} = sign_json_jose(PrivateKey, ReqBody, Nonce),
%% Encode the Signed body with jiffy %% Encode the Signed body with jiffy
FinalBody = jiffy:encode(SignedBody), FinalBody = jiffy:encode(SignedBody),
Options = [], Options = [],
@ -58,30 +62,26 @@ new_account(NewAccURl, PrivateKey, Req, Nonce) ->
{ok, {{_, Code, _}, Head, Body}} when Code >= 200, Code =< 299 -> {ok, {{_, Code, _}, Head, Body}} when Code >= 200, Code =< 299 ->
%% Decode the json string %% Decode the json string
{Return} = jiffy:decode(Body), {Return} = jiffy:decode(Body),
TOSUrl = get_TOS(Head), TOSUrl = get_tos(Head),
% Find and save the replay nonce % Find and save the replay nonce
NewNonce = get_nonce(Head), NewNonce = get_nonce(Head),
{ok, {TOSUrl, Return}, NewNonce}; {ok, {TOSUrl, Return}, NewNonce};
{ok, {{_, 409 = Code, _}, Head, Body}} -> {ok, {{_, Code, _}, _Head, Body}} ->
?ERROR_MSG("Got status code: ~B from <~s>, Body: ~s",
[NewAccURl, Code, Body]),
NewNonce = get_nonce(Head),
{error, key_in_use, NewNonce};
{ok, {{_, Code, _}, Head, Body}} ->
?ERROR_MSG("Got unexpected status code from <~s>: ~B, Body: ~s", ?ERROR_MSG("Got unexpected status code from <~s>: ~B, Body: ~s",
[NewAccURl, Code, Body]), [NewAccURl, Code, Body]),
NewNonce = get_nonce(Head), {error, unexpected_code};
{error, unexpected_code, NewNonce};
{error, Reason} -> {error, Reason} ->
?ERROR_MSG("Error requesting directory from <~s>: ~p", ?ERROR_MSG("Error requesting directory from <~s>: ~p",
[NewAccURl, Reason]), [NewAccURl, Reason]),
{error, Reason, Nonce} {error, Reason}
end. end.
-spec update_account(url(), jose_jwk:key(), proplist(), nonce()) ->
{ok, proplist(), nonce()} | {error, _}.
update_account(AccURl, PrivateKey, Req, Nonce) -> update_account(AccURl, PrivateKey, Req, Nonce) ->
%% Make the request body %% Make the request body
ReqBody = jiffy:encode({[{ <<"resource">>, <<"reg">>}] ++ Req}), ReqBody = jiffy:encode({[{ <<"resource">>, <<"reg">>}] ++ Req}),
{_, SignedBody} = sign_json_jose(PrivateKey, ReqBody, AccURl, Nonce), {_, SignedBody} = sign_json_jose(PrivateKey, ReqBody, Nonce),
%% Encode the Signed body with jiffy %% Encode the Signed body with jiffy
FinalBody = jiffy:encode(SignedBody), FinalBody = jiffy:encode(SignedBody),
Options = [], Options = [],
@ -94,25 +94,23 @@ update_account(AccURl, PrivateKey, Req, Nonce) ->
% Find and save the replay nonce % Find and save the replay nonce
NewNonce = get_nonce(Head), NewNonce = get_nonce(Head),
{ok, Return, NewNonce}; {ok, Return, NewNonce};
{ok, {{_, Code, _}, Head, Body}} -> {ok, {{_, Code, _}, _Head, Body}} ->
?ERROR_MSG("Got unexpected status code from <~s>: ~B, Body: ~s", ?ERROR_MSG("Got unexpected status code from <~s>: ~B, Body: ~s",
[AccURl, Code, Body]), [AccURl, Code, Body]),
NewNonce = get_nonce(Head), {error, unexpected_code};
{error, unexpected_code, NewNonce};
{error, Reason} -> {error, Reason} ->
?ERROR_MSG("Error requesting directory from <~s>: ~p", ?ERROR_MSG("Error requesting directory from <~s>: ~p",
[AccURl, Reason]), [AccURl, Reason]),
{error, Reason, Nonce} {error, Reason}
end. end.
-spec get_account(url(), jose_jwk:key(), nonce()) ->
{ok, {url(), proplist()}, nonce()} | {error, _}.
get_account(AccURl, PrivateKey, Nonce) -> get_account(AccURl, PrivateKey, Nonce) ->
%% Make the request body %% Make the request body
ReqBody = jiffy:encode({[ ReqBody = jiffy:encode({[{<<"resource">>, <<"reg">>}]}),
{ <<"resource">>, <<"reg">>}
]}),
%% Jose Sign %% Jose Sign
{_, SignedBody} = sign_json_jose(PrivateKey, ReqBody, AccURl, Nonce), {_, SignedBody} = sign_json_jose(PrivateKey, ReqBody, Nonce),
%% Encode the Signed body with jiffy %% Encode the Signed body with jiffy
FinalBody = jiffy:encode(SignedBody), FinalBody = jiffy:encode(SignedBody),
Options = [], Options = [],
@ -122,33 +120,35 @@ get_account(AccURl, PrivateKey, Nonce) ->
{ok, {{_, Code, _}, Head, Body}} when Code >= 200, Code =< 299 -> {ok, {{_, Code, _}, Head, Body}} when Code >= 200, Code =< 299 ->
%% Decode the json string %% Decode the json string
{Return} = jiffy:decode(Body), {Return} = jiffy:decode(Body),
TOSUrl = get_TOS(Head), TOSUrl = get_tos(Head),
% Find and save the replay nonce % Find and save the replay nonce
NewNonce = get_nonce(Head), NewNonce = get_nonce(Head),
{ok, {TOSUrl, Return}, NewNonce}; {ok, {TOSUrl, Return}, NewNonce};
{ok, {{_, Code, _}, Head, Body}} -> {ok, {{_, Code, _}, _Head, Body}} ->
?ERROR_MSG("Got unexpected status code from <~s>: ~B, Head: ~s", ?ERROR_MSG("Got unexpected status code from <~s>: ~B, Head: ~s",
[AccURl, Code, Body]), [AccURl, Code, Body]),
NewNonce = get_nonce(Head), {error, unexpected_code};
{error, unexpected_code, NewNonce};
{error, Reason} -> {error, Reason} ->
?ERROR_MSG("Error requesting directory from <~s>: ~p", ?ERROR_MSG("Error requesting directory from <~s>: ~p",
[AccURl, Reason]), [AccURl, Reason]),
{error, Reason, Nonce} {error, Reason}
end. end.
%% %%
%% Useful funs %% Useful funs
%% %%
-spec get_nonce(proplist()) -> nonce() | 'none'.
get_nonce(Head) -> get_nonce(Head) ->
{"replay-nonce", Nonce} = proplists:lookup("replay-nonce", Head), case proplists:lookup("replay-nonce", Head) of
Nonce. {"replay-nonce", Nonce} -> Nonce;
none -> none
end.
%% Very bad way to extract this %% Very bad way to extract this
%% TODO: Find a better way %% TODO: Find a better way
get_TOS(Head) -> -spec get_tos(proplist()) -> url() | 'none'.
get_tos(Head) ->
try try
[{_, Link}] = [{K, V} || {K, V} <- Head, [{_, Link}] = [{K, V} || {K, V} <- Head,
K =:= "link" andalso lists:suffix("\"terms-of-service\"", V)], K =:= "link" andalso lists:suffix("\"terms-of-service\"", V)],
@ -157,16 +157,15 @@ get_TOS(Head) ->
string:strip(Link2, right, $>) string:strip(Link2, right, $>)
catch catch
_:_ -> _:_ ->
no_tos none
end. end.
-spec sign_json_jose(jose_jwk:key(), string(), nonce()) -> jws().
sign_json_jose(Key, Json, Url, Nonce) -> sign_json_jose(Key, Json, Nonce) ->
% Generate a public key % Generate a public key
PubKey = jose_jwk:to_public(Key), PubKey = jose_jwk:to_public(Key),
{_, BinaryPubKey} = jose_jwk:to_binary(PubKey), {_, BinaryPubKey} = jose_jwk:to_binary(PubKey),
PubKeyJson = jiffy:decode(BinaryPubKey), PubKeyJson = jiffy:decode(BinaryPubKey),
% Jws object containing the algorithm % Jws object containing the algorithm
%% TODO: Dont hardcode the alg %% TODO: Dont hardcode the alg
JwsObj = jose_jws:from( JwsObj = jose_jws:from(
@ -185,17 +184,16 @@ sign_json_jose(Key, Json, Url, Nonce) ->
%% A typical acme workflow %% A typical acme workflow
scenario(CAUrl, AccId, PrivateKey) -> scenario(CAUrl, AccId, PrivateKey) ->
DirURL = CAUrl ++ "/directory",
DirURL = CAUrl ++ "/" ++ ?DIRURL,
{ok, Dirs, Nonce0} = directory(DirURL), {ok, Dirs, Nonce0} = directory(DirURL),
AccURL = CAUrl ++ ?REGURL ++ AccId, AccURL = CAUrl ++ "/acme/reg/" ++ AccId,
{ok, {_TOS, Account}, Nonce1} = get_account(AccURL, PrivateKey, Nonce0). {ok, {_TOS, Account}, Nonce1} = get_account(AccURL, PrivateKey, Nonce0).
new_user_scenario(CAUrl) -> new_user_scenario(CAUrl) ->
PrivateKey = generate_key(), PrivateKey = generate_key(),
DirURL = CAUrl ++ "/" ++ ?DIRURL, DirURL = CAUrl ++ "/directory",
{ok, Dirs, Nonce0} = directory(DirURL), {ok, Dirs, Nonce0} = directory(DirURL),
#{"new-reg" := NewAccURL} = Dirs, #{"new-reg" := NewAccURL} = Dirs,
@ -203,7 +201,7 @@ new_user_scenario(CAUrl) ->
{ok, {TOS, Account}, Nonce1} = new_account(NewAccURL, PrivateKey, Req0, Nonce0), {ok, {TOS, Account}, Nonce1} = new_account(NewAccURL, PrivateKey, Req0, Nonce0),
{_, AccId} = proplists:lookup(<<"id">>, Account), {_, AccId} = proplists:lookup(<<"id">>, Account),
AccURL = CAUrl ++ ?REGURL ++ integer_to_list(AccId), AccURL = CAUrl ++ "/acme/reg/" ++ integer_to_list(AccId),
Req1 = [{ <<"agreement">>, list_to_bitstring(TOS)}], Req1 = [{ <<"agreement">>, list_to_bitstring(TOS)}],
{ok, Account1, Nonce2} = update_account(AccURL, PrivateKey, Req1, Nonce1), {ok, Account1, Nonce2} = update_account(AccURL, PrivateKey, Req1, Nonce1),
@ -213,7 +211,7 @@ generate_key() ->
jose_jwk:generate_key({ec, secp256r1}). jose_jwk:generate_key({ec, secp256r1}).
%% Just a test %% Just a test
scenario0() -> scenario0(KeyFile) ->
PrivateKey = jose_jwk:from_file(?DEFAULT_KEY_FILE), PrivateKey = jose_jwk:from_file(KeyFile),
% scenario("http://localhost:4000", "2", PrivateKey). % scenario("http://localhost:4000", "2", PrivateKey).
new_user_scenario("http://localhost:4000"). new_user_scenario("http://localhost:4000").