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:
parent
53d47483c8
commit
167edacb5f
@ -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").
|
||||||
|
Loading…
Reference in New Issue
Block a user