Epic/td 651/deploy akm (#12)

* add logging

* debug

* debug

* fix auth context

* fix auth context

* maybe fix release

* fix release deps

* fix authority config

* fix auth context

* fix api_key entity

* fix mailer

* fix test

* debug revoke

* fix api_key entity

* debug auth context

* add entities to context

* debug revoke

* debug revoke

* debug revoke

* fix auth context

* debug email

* fix revoke

* fix auth context for revoke

* fix style

* delete headers from revoke method

* cleanup

---------

Co-authored-by: anatoliy.losev <losto@nix>
This commit is contained in:
ttt161 2023-08-07 11:46:13 +03:00 committed by GitHub
parent 9c3e1f3968
commit d9169e2bdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 149 additions and 66 deletions

View File

@ -1 +1,6 @@
Subject: Revoke key
From: no-reply@empayre.com
To: You
To revoke key, go to link: {{ url }}/apikeys/v2/orgs/{{ party_id }}/revoke-api-key/{{ api_key_id }}?apiKeyRevokeToken={{ revoke_token }} To revoke key, go to link: {{ url }}/apikeys/v2/orgs/{{ party_id }}/revoke-api-key/{{ api_key_id }}?apiKeyRevokeToken={{ revoke_token }}

View File

@ -78,13 +78,15 @@ prepare(OperationID = 'IssueApiKey', #{'partyId' := PartyID, 'ApiKeyIssue' := Ap
end, end,
{ok, #{authorize => Authorize, process => Process}}; {ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetApiKey', #{'partyId' := PartyID, 'apiKeyId' := ApiKeyId}, Context, _Opts) -> prepare(OperationID = 'GetApiKey', #{'partyId' := PartyID, 'apiKeyId' := ApiKeyId}, Context, _Opts) ->
Result = akm_apikeys_processing:get_api_key(ApiKeyId),
Authorize = fun() -> Authorize = fun() ->
Prototypes = [{operation, #{id => OperationID, party => PartyID}}], ApiKey = extract_api_key(Result),
Prototypes = [{operation, #{id => OperationID, party => PartyID, api_key => ApiKey}}],
Resolution = akm_auth:authorize_operation(Prototypes, Context), Resolution = akm_auth:authorize_operation(Prototypes, Context),
{ok, Resolution} {ok, Resolution}
end, end,
Process = fun() -> Process = fun() ->
case akm_apikeys_processing:get_api_key(ApiKeyId, PartyID) of case Result of
{ok, ApiKey} -> {ok, ApiKey} ->
akm_handler_utils:reply_ok(200, ApiKey); akm_handler_utils:reply_ok(200, ApiKey);
{error, not_found} -> {error, not_found} ->
@ -121,8 +123,10 @@ prepare(OperationID = 'RequestRevokeApiKey', Params, Context, _Opts) ->
'apiKeyId' := ApiKeyId, 'apiKeyId' := ApiKeyId,
'RequestRevoke' := #{<<"status">> := Status} 'RequestRevoke' := #{<<"status">> := Status}
} = Params, } = Params,
Result = akm_apikeys_processing:get_api_key(ApiKeyId),
Authorize = fun() -> Authorize = fun() ->
Prototypes = [{operation, #{id => OperationID, party => PartyID}}], ApiKey = extract_api_key(Result),
Prototypes = [{operation, #{id => OperationID, party => PartyID, api_key => ApiKey}}],
Resolution = akm_auth:authorize_operation(Prototypes, Context), Resolution = akm_auth:authorize_operation(Prototypes, Context),
{ok, Resolution} {ok, Resolution}
end, end,
@ -137,18 +141,21 @@ prepare(OperationID = 'RequestRevokeApiKey', Params, Context, _Opts) ->
end, end,
{ok, #{authorize => Authorize, process => Process}}; {ok, #{authorize => Authorize, process => Process}};
prepare( prepare(
OperationID = 'RevokeApiKey', _OperationID = 'RevokeApiKey',
#{'partyId' := PartyID, 'apiKeyId' := ApiKeyId, 'apiKeyRevokeToken' := Token}, #{'partyId' := _PartyID, 'apiKeyId' := ApiKeyId, 'apiKeyRevokeToken' := Token},
Context, _Context,
_Opts _Opts
) -> ) ->
%% Result = akm_apikeys_processing:get_api_key(ApiKeyId),
Authorize = fun() -> Authorize = fun() ->
Prototypes = [{operation, #{id => OperationID, party => PartyID}}], %% ApiKey = extract_api_key(Result),
Resolution = akm_auth:authorize_operation(Prototypes, Context), %% Prototypes = [{operation, #{id => OperationID, party => PartyID, api_key => ApiKey}}],
{ok, Resolution} %% Resolution = akm_auth:authorize_operation(Prototypes, Context),
%% {ok, Resolution}
{ok, allowed}
end, end,
Process = fun() -> Process = fun() ->
case akm_apikeys_processing:revoke(PartyID, ApiKeyId, Token) of case akm_apikeys_processing:revoke(ApiKeyId, Token) of
ok -> ok ->
akm_handler_utils:reply_ok(204); akm_handler_utils:reply_ok(204);
{error, not_found} -> {error, not_found} ->
@ -156,3 +163,8 @@ prepare(
end end
end, end,
{ok, #{authorize => Authorize, process => Process}}. {ok, #{authorize => Authorize, process => Process}}.
extract_api_key({ok, Apikey}) ->
Apikey;
extract_api_key(_) ->
undefined.

View File

@ -5,10 +5,10 @@
-include_lib("epgsql/include/epgsql.hrl"). -include_lib("epgsql/include/epgsql.hrl").
-export([issue_api_key/3]). -export([issue_api_key/3]).
-export([get_api_key/2]). -export([get_api_key/1]).
-export([list_api_keys/4]). -export([list_api_keys/4]).
-export([request_revoke/4]). -export([request_revoke/4]).
-export([revoke/3]). -export([revoke/2]).
-type list_keys_response() :: #{ -type list_keys_response() :: #{
results => [map()], results => [map()],
@ -50,12 +50,12 @@ issue_api_key(PartyID, #{<<"name">> := Name} = ApiKey0, WoodyContext) ->
{error, already_exists} {error, already_exists}
end. end.
-spec get_api_key(binary(), binary()) -> {ok, map()} | {error, not_found}. -spec get_api_key(binary()) -> {ok, map()} | {error, not_found}.
get_api_key(ApiKeyId, PartyId) -> get_api_key(ApiKeyId) ->
Result = epgsql_pool:query( Result = epgsql_pool:query(
main_pool, main_pool,
"SELECT id, name, status, metadata, created_at FROM apikeys WHERE id = $1 AND party_id = $2", "SELECT id, name, status, metadata, created_at FROM apikeys WHERE id = $1",
[ApiKeyId, PartyId] [ApiKeyId]
), ),
case Result of case Result of
{ok, _Columns, []} -> {ok, _Columns, []} ->
@ -87,7 +87,7 @@ list_api_keys(PartyId, Status, Limit, Offset) ->
-spec request_revoke(binary(), binary(), binary(), binary()) -> -spec request_revoke(binary(), binary(), binary(), binary()) ->
{ok, revoke_email_sent} | {error, not_found}. {ok, revoke_email_sent} | {error, not_found}.
request_revoke(Email, PartyID, ApiKeyId, Status) -> request_revoke(Email, PartyID, ApiKeyId, Status) ->
case get_full_api_key(ApiKeyId, PartyID) of case get_full_api_key(ApiKeyId) of
{error, not_found} -> {error, not_found} ->
{error, not_found}; {error, not_found};
{ok, _ApiKey} -> {ok, _ApiKey} ->
@ -100,8 +100,8 @@ request_revoke(Email, PartyID, ApiKeyId, Status) ->
epgsql_pool:query( epgsql_pool:query(
Worker, Worker,
"UPDATE apikeys SET pending_status = $1, revoke_token = $2 " "UPDATE apikeys SET pending_status = $1, revoke_token = $2 "
"WHERE id = $3 AND party_id = $4", "WHERE id = $3",
[Status, Token, ApiKeyId, PartyID] [Status, Token, ApiKeyId]
) )
end end
) )
@ -109,22 +109,23 @@ request_revoke(Email, PartyID, ApiKeyId, Status) ->
{ok, 1} -> {ok, 1} ->
{ok, revoke_email_sent} {ok, revoke_email_sent}
catch catch
_Ex:_Er -> Ex:Er ->
logger:error("Failed to send email with ~p:~p", [Ex, Er]),
error(failed_to_send_email) error(failed_to_send_email)
end end
end. end.
-spec revoke(binary(), binary(), binary()) -> ok | {error, not_found}. -spec revoke(binary(), binary()) -> ok | {error, not_found}.
revoke(PartyId, ApiKeyId, RevokeToken) -> revoke(ApiKeyId, RevokeToken) ->
case get_full_api_key(ApiKeyId, PartyId) of case get_full_api_key(ApiKeyId) of
{ok, #{ {ok, #{
<<"pending_status">> := PendingStatus, <<"pending_status">> := PendingStatus,
<<"revoke_token">> := RevokeToken <<"revoke_token">> := RevokeToken
}} -> }} ->
{ok, 1} = epgsql_pool:query( {ok, 1} = epgsql_pool:query(
main_pool, main_pool,
"UPDATE apikeys SET status = $1, revoke_token = null WHERE id = $2 AND party_id = $3", "UPDATE apikeys SET status = $1, revoke_token = null WHERE id = $2",
[PendingStatus, ApiKeyId, PartyId] [PendingStatus, ApiKeyId]
), ),
ok; ok;
_ -> _ ->
@ -134,13 +135,13 @@ revoke(PartyId, ApiKeyId, RevokeToken) ->
%% Internal functions %% Internal functions
get_authority_id() -> get_authority_id() ->
application:get_env(akm, authority_id). application:get_env(akm, authority_id, undefined).
get_full_api_key(ApiKeyId, PartyId) -> get_full_api_key(ApiKeyId) ->
Result = epgsql_pool:query( Result = epgsql_pool:query(
main_pool, main_pool,
"SELECT * FROM apikeys WHERE id = $1 AND party_id = $2", "SELECT * FROM apikeys WHERE id = $1",
[ApiKeyId, PartyId] [ApiKeyId]
), ),
case Result of case Result of
{ok, _Columns, []} -> {ok, _Columns, []} ->

View File

@ -2,6 +2,8 @@
-define(APP, akm). -define(APP, akm).
-include_lib("bouncer_proto/include/bouncer_ctx_thrift.hrl").
-export([get_subject_id/1]). -export([get_subject_id/1]).
-export([get_party_id/1]). -export([get_party_id/1]).
-export([get_user_id/1]). -export([get_user_id/1]).
@ -12,6 +14,8 @@
-export([authorize_api_key/3]). -export([authorize_api_key/3]).
-export([authorize_operation/2]). -export([authorize_operation/2]).
-export([make_auth_context/1]).
-export_type([resolution/0]). -export_type([resolution/0]).
-export_type([preauth_context/0]). -export_type([preauth_context/0]).
-export_type([auth_context/0]). -export_type([auth_context/0]).
@ -97,6 +101,19 @@ authorize_operation(Prototypes, Context) ->
Fragments1 = akm_bouncer_context:build(Prototypes, Fragments), Fragments1 = akm_bouncer_context:build(Prototypes, Fragments),
akm_bouncer:judge(Fragments1, WoodyContext). akm_bouncer:judge(Fragments1, WoodyContext).
-spec make_auth_context(binary()) -> auth_context().
make_auth_context(PartyId) ->
{
authorized,
#{
status => active,
context => #ctx_ContextFragment{type = 'v1_thrift_binary'},
metadata => #{
get_metadata_mapped_key(party_id) => PartyId
}
}
}.
%% %%
get_token_keeper_fragment(?AUTHORIZED(#{context := Context})) -> get_token_keeper_fragment(?AUTHORIZED(#{context := Context})) ->

View File

@ -20,7 +20,7 @@ gather_context_fragments(TokenContextFragment, UserID, IPAddress, WoodyCtx) ->
judge({Acc, External}, WoodyCtx) -> judge({Acc, External}, WoodyCtx) ->
% TODO error out early? % TODO error out early?
{ok, RulesetID} = application:get_env(akm, bouncer_ruleset_id), {ok, RulesetID} = application:get_env(akm, bouncer_ruleset_id),
JudgeContext = #{fragments => External#{<<"akm">> => Acc}}, JudgeContext = #{fragments => External#{<<"apikeymgmt">> => Acc}},
bouncer_client:judge(RulesetID, JudgeContext, WoodyCtx). bouncer_client:judge(RulesetID, JudgeContext, WoodyCtx).
%% %%

View File

@ -19,7 +19,8 @@
-type prototype_operation() :: #{ -type prototype_operation() :: #{
id => operation_id(), id => operation_id(),
party => maybe_undefined(entity_id()) party => maybe_undefined(entity_id()),
api_key => maybe_undefined(entity_id())
}. }.
-type entity_id() :: binary(). -type entity_id() :: binary().
@ -49,28 +50,45 @@ build(Prototypes, {Acc0, External}) ->
{Acc1, External}. {Acc1, External}.
build(operation, Params = #{id := OperationID}, Acc) -> build(operation, Params = #{id := OperationID}, Acc) ->
Acc#ctx_v1_ContextFragment{ PartyEntity = party_entity(Params),
ApiKeyEntity = api_key_entity(Params),
ListEntities = lists:filter(fun(E) -> E =/= undefined end, [PartyEntity, ApiKeyEntity]),
Ctx = Acc#ctx_v1_ContextFragment{
apikeymgmt = #ctx_v1_ContextApiKeyMgmt{ apikeymgmt = #ctx_v1_ContextApiKeyMgmt{
op = #ctx_v1_ApiKeyMgmtOperation{ op = #ctx_v1_ApiKeyMgmtOperation{
id = operation_id_to_binary(OperationID), id = operation_id_to_binary(OperationID),
party = maybe_entity(party_id, Params), party = PartyEntity,
api_key = maybe(api_key, Params) api_key = ApiKeyEntity
} }
} }
}. },
maybe_add_entities(Ctx, ListEntities).
%% %%
maybe(Name, Params) -> api_key_entity(
maps:get(Name, Params, undefined). #{
api_key := #{
<<"id">> := ApiKeyId,
<<"metadata">> := #{<<"party.id">> := PartyId}
}
}
) ->
#base_Entity{id = ApiKeyId, party = PartyId, type = <<"ApiKey">>};
api_key_entity(_) ->
undefined.
maybe_entity(Name, Params) -> party_entity(#{party := PartyId}) ->
case maps:get(Name, Params, undefined) of #base_Entity{id = PartyId};
undefined -> party_entity(_) ->
undefined; undefined.
Value ->
#base_Entity{id = Value}
end.
operation_id_to_binary(V) -> operation_id_to_binary(V) ->
erlang:atom_to_binary(V, utf8). erlang:atom_to_binary(V, utf8).
maybe_add_entities(Ctx, []) ->
Ctx;
maybe_add_entities(Ctx, ListEntities) ->
Ctx#ctx_v1_ContextFragment{
entities = ordsets:from_list(ListEntities)
}.

View File

@ -60,7 +60,7 @@ authorize_api_key(OperationID, ApiKey, _Context, _HandlerOpts) ->
%% request validation checks before this stage. %% request validation checks before this stage.
%% But since a decent chunk of authorization logic is already defined in the handler function %% But since a decent chunk of authorization logic is already defined in the handler function
%% it is probably easier to move it there in its entirety. %% it is probably easier to move it there in its entirety.
ok = scoper:add_scope('swag.server', #{api => wallet, operation_id => OperationID}), ok = scoper:add_scope('swag.server', #{api => apikeymgmt, operation_id => OperationID}),
case akm_auth:preauthorize_api_key(ApiKey) of case akm_auth:preauthorize_api_key(ApiKey) of
{ok, Context} -> {ok, Context} ->
{true, Context}; {true, Context};
@ -77,7 +77,7 @@ authorize_api_key(OperationID, ApiKey, _Context, _HandlerOpts) ->
) -> ) ->
akm_apikeys_handler:request_result(). akm_apikeys_handler:request_result().
handle_request(OperationID, Req, SwagContext, Opts) -> handle_request(OperationID, Req, SwagContext, Opts) ->
#{'X-Request-Deadline' := Header} = Req, Header = maps:get('X-Request-Deadline', Req, undefined),
case akm_utils:parse_deadline(Header) of case akm_utils:parse_deadline(Header) of
{ok, Deadline} -> {ok, Deadline} ->
WoodyContext = attach_deadline(Deadline, create_woody_context(Req)), WoodyContext = attach_deadline(Deadline, create_woody_context(Req)),
@ -93,7 +93,7 @@ handle_request(OperationID, Req, SwagContext, Opts) ->
process_request(OperationID, Req, SwagContext0, Opts, WoodyContext0) -> process_request(OperationID, Req, SwagContext0, Opts, WoodyContext0) ->
_ = logger:info("Processing request ~p", [OperationID]), _ = logger:info("Processing request ~p", [OperationID]),
try try
SwagContext = do_authorize_api_key(SwagContext0, WoodyContext0), SwagContext = do_authorize_api_key(OperationID, SwagContext0, WoodyContext0),
WoodyContext = put_user_identity(WoodyContext0, get_auth_context(SwagContext)), WoodyContext = put_user_identity(WoodyContext0, get_auth_context(SwagContext)),
Context = create_handler_context(OperationID, SwagContext, WoodyContext), Context = create_handler_context(OperationID, SwagContext, WoodyContext),
ok = set_context_meta(Context), ok = set_context_meta(Context),
@ -117,7 +117,9 @@ process_request(OperationID, Req, SwagContext0, Opts, WoodyContext0) ->
end. end.
-spec create_woody_context(akm_apikeys_handler:request_data()) -> woody_context:ctx(). -spec create_woody_context(akm_apikeys_handler:request_data()) -> woody_context:ctx().
create_woody_context(#{'X-Request-ID' := RequestID}) -> create_woody_context(RequestData) ->
%% use dynamic request_id if not presented
RequestID = maps:get('X-Request-ID', RequestData, new_request_id()),
RpcID = #{trace_id := TraceID} = woody_context:new_rpc_id(genlib:to_binary(RequestID)), RpcID = #{trace_id := TraceID} = woody_context:new_rpc_id(genlib:to_binary(RequestID)),
ok = scoper:add_meta(#{request_id => RequestID, trace_id => TraceID}), ok = scoper:add_meta(#{request_id => RequestID, trace_id => TraceID}),
woody_context:new(RpcID, undefined, akm_woody_client:get_service_deadline(akm)). woody_context:new(RpcID, undefined, akm_woody_client:get_service_deadline(akm)).
@ -151,7 +153,10 @@ attach_deadline(undefined, Context) ->
attach_deadline(Deadline, Context) -> attach_deadline(Deadline, Context) ->
woody_context:set_deadline(Deadline, Context). woody_context:set_deadline(Deadline, Context).
do_authorize_api_key(SwagContext = #{auth_context := PreAuthContext}, WoodyContext) -> do_authorize_api_key('RevokeApiKey', #{cowboy_req := Req} = SwagContext, _WoodyContext) ->
PartyId = cowboy_req:binding(partyId, Req),
SwagContext#{auth_context => akm_auth:make_auth_context(PartyId)};
do_authorize_api_key(_OperationID, SwagContext = #{auth_context := PreAuthContext}, WoodyContext) ->
case akm_auth:authorize_api_key(PreAuthContext, make_token_context(SwagContext), WoodyContext) of case akm_auth:authorize_api_key(PreAuthContext, make_token_context(SwagContext), WoodyContext) of
{ok, AuthContext} -> {ok, AuthContext} ->
SwagContext#{auth_context => AuthContext}; SwagContext#{auth_context => AuthContext};
@ -188,3 +193,6 @@ process_woody_error(_Source, resource_unavailable, _Details) ->
akm_handler_utils:reply_error(504); akm_handler_utils:reply_error(504);
process_woody_error(_Source, result_unknown, _Details) -> process_woody_error(_Source, result_unknown, _Details) ->
akm_handler_utils:reply_error(504). akm_handler_utils:reply_error(504).
new_request_id() ->
base64:encode(crypto:strong_rand_bytes(24)).

View File

@ -19,12 +19,19 @@ send_revoke_mail(Email, PartyID, ApiKeyID, Token) ->
{api_key_id, ApiKeyID}, {api_key_id, ApiKeyID},
{revoke_token, Token} {revoke_token, Token}
]), ]),
BinaryBody = erlang:iolist_to_binary(Body), BinaryBody = unicode:characters_to_binary(Body),
logger:info("Try send email with body: ~p", [BinaryBody]),
Pid = self(), Pid = self(),
case case
gen_smtp_client:send( gen_smtp_client:send(
{from_email(), [Email], BinaryBody}, {from_email(), [Email], BinaryBody},
[{relay, relay()}, {username, username()}, {password, password()}], [
{ssl, true},
{relay, relay()},
{port, port()},
{username, username()},
{password, password()}
],
fun(Result) -> erlang:send(Pid, {sending_result, Result}) end fun(Result) -> erlang:send(Pid, {sending_result, Result}) end
) )
of of
@ -54,9 +61,17 @@ password() ->
#{password := Password} = get_env(), #{password := Password} = get_env(),
Password. Password.
timeout() ->
maps:get(timeout, get_env(), 3000).
port() ->
#{port := Port} = get_env(),
to_int(Port).
get_env() -> get_env() ->
genlib_app:env(akm, mailer, #{ genlib_app:env(akm, mailer, #{
url => "vality.dev", url => "https://vality.dev",
port => 465,
from_email => "example@example.com", from_email => "example@example.com",
relay => "smtp.gmail.com", relay => "smtp.gmail.com",
username => "username", username => "username",
@ -65,11 +80,16 @@ get_env() ->
}). }).
wait_result() -> wait_result() ->
Timeout = timeout(),
receive receive
{sending_result, {ok, _Receipt}} -> {sending_result, {ok, _Receipt}} ->
ok; ok;
{sending_result, Error} -> {sending_result, Error} ->
{error, Error} {error, Error}
after 3000 -> after Timeout ->
{error, {failed_to_send, sending_email_timeout}} {error, {failed_to_send, sending_email_timeout}}
end. end.
to_int(Value) when is_integer(Value) -> Value;
to_int(Value) when is_binary(Value) -> erlang:binary_to_integer(Value);
to_int(Value) when is_list(Value) -> erlang:list_to_integer(Value).

View File

@ -71,11 +71,7 @@ request_revoke_key(Host, Port, PartyId, ApiKeyId) ->
-spec revoke_key(inet:hostname() | inet:ip_address(), inet:port_number(), binary()) -> any(). -spec revoke_key(inet:hostname() | inet:ip_address(), inet:port_number(), binary()) -> any().
revoke_key(Host, Port, PathWithQuery) -> revoke_key(Host, Port, PathWithQuery) ->
Headers = [ Headers = [],
{<<"X-Request-ID">>, <<"revoke_key">>},
{<<"content-type">>, <<"application/json; charset=utf-8">>},
{<<"Authorization">>, <<"Bearer sffsdfsfsdfsdfs">>}
],
ConnPid = connect(Host, Port), ConnPid = connect(Host, Port),
Answer = get(ConnPid, PathWithQuery, Headers), Answer = get(ConnPid, PathWithQuery, Headers),
disconnect(ConnPid), disconnect(ConnPid),

View File

@ -100,6 +100,7 @@ prepare_config(State) ->
{mailer, #{ {mailer, #{
url => "http://vality.dev", url => "http://vality.dev",
port => 465,
from_email => "example@example.com", from_email => "example@example.com",
relay => "smtp4dev", relay => "smtp4dev",
password => "password", password => "password",
@ -119,8 +120,8 @@ prepare_config(State) ->
mock_services(State) -> mock_services(State) ->
meck:expect( meck:expect(
akm_auth, akm_bouncer,
authorize_operation, judge,
fun(_, _) -> allowed end fun(_, _) -> allowed end
), ),
meck:expect( meck:expect(

View File

@ -23,7 +23,8 @@
{elvis_style, atom_naming_convention, #{ {elvis_style, atom_naming_convention, #{
ignore => [ ignore => [
akm_apikeys_handler, akm_apikeys_handler,
akm_apikeys_processing akm_apikeys_processing,
akm_handler
] ]
}}, }},
{elvis_style, invalid_dynamic_call, #{ {elvis_style, invalid_dynamic_call, #{

View File

@ -39,8 +39,6 @@
{woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {branch, "master"}}}, {woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {branch, "master"}}},
{bouncer_proto, {git, "https://github.com/valitydev/bouncer-proto.git", {branch, "master"}}}, {bouncer_proto, {git, "https://github.com/valitydev/bouncer-proto.git", {branch, "master"}}},
{bouncer_client, {git, "https://github.com/valitydev/bouncer-client-erlang", {branch, "master"}}}, {bouncer_client, {git, "https://github.com/valitydev/bouncer-client-erlang", {branch, "master"}}},
{epgsql, {git, "https://github.com/epgsql/epgsql.git", {tag, "4.7.1"}}},
{epgsql_pool, {git, "https://github.com/wgnet/epgsql_pool", {branch, "master"}}},
{token_keeper_client, {git, "https://github.com/valitydev/token-keeper-client", {branch, "master"}}}, {token_keeper_client, {git, "https://github.com/valitydev/token-keeper-client", {branch, "master"}}},
%% Libraries generated with swagger-codegen-erlang from valitydev/swag-api-keys %% Libraries generated with swagger-codegen-erlang from valitydev/swag-api-keys
@ -49,6 +47,11 @@
{swag_client_apikeys, {swag_client_apikeys,
{git, "https://github.com/valitydev/swag-api-keys-v2.git", {branch, "release/erlang/client/master"}}}, {git, "https://github.com/valitydev/swag-api-keys-v2.git", {branch, "release/erlang/client/master"}}},
%% Libraries for postgres interaction
{epgsql, {git, "https://github.com/epgsql/epgsql.git", {tag, "4.7.1"}}},
{epgsql_pool, {git, "https://github.com/wgnet/epgsql_pool", {branch, "master"}}},
{herd, {git, "https://github.com/wgnet/herd.git", {tag, "1.3.4"}}},
%% NOTE %% NOTE
%% Pinning to version "1.11.2" from hex here causes constant upgrading and recompilation of the entire project %% Pinning to version "1.11.2" from hex here causes constant upgrading and recompilation of the entire project
{jose, {git, "https://github.com/potatosalad/erlang-jose.git", {tag, "1.11.2"}}}, {jose, {git, "https://github.com/potatosalad/erlang-jose.git", {tag, "1.11.2"}}},
@ -106,6 +109,7 @@
prometheus, prometheus,
prometheus_cowboy, prometheus_cowboy,
sasl, sasl,
herd,
akm akm
]}, ]},
{sys_config, "./config/sys.config"}, {sys_config, "./config/sys.config"},

View File

@ -90,7 +90,7 @@
{<<"herd">>, {<<"herd">>,
{git,"https://github.com/wgnet/herd.git", {git,"https://github.com/wgnet/herd.git",
{ref,"934847589dcf5a6d2b02a1f546ffe91c04066f17"}}, {ref,"934847589dcf5a6d2b02a1f546ffe91c04066f17"}},
1}, 0},
{<<"identdocstore_proto">>, {<<"identdocstore_proto">>,
{git,"https://github.com/valitydev/identdocstore-proto.git", {git,"https://github.com/valitydev/identdocstore-proto.git",
{ref,"0ab676da2bb23eb04c42e02325c40c413d74856e"}}, {ref,"0ab676da2bb23eb04c42e02325c40c413d74856e"}},
@ -133,11 +133,11 @@
{<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.7">>},2}, {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.7">>},2},
{<<"swag_client_apikeys">>, {<<"swag_client_apikeys">>,
{git,"https://github.com/valitydev/swag-api-keys-v2.git", {git,"https://github.com/valitydev/swag-api-keys-v2.git",
{ref,"de86e82de67071276030186f4de806f1a7ff0431"}}, {ref,"dd3ccc414fc7b08a9b62acad7aefdbc600566062"}},
0}, 0},
{<<"swag_server_apikeys">>, {<<"swag_server_apikeys">>,
{git,"https://github.com/valitydev/swag-api-keys-v2.git", {git,"https://github.com/valitydev/swag-api-keys-v2.git",
{ref,"5e27ca5e3aa6f4b44b9677e870e5c8d557fee773"}}, {ref,"a0f3b2d46e9eba46c89b3bf81145629da8bf0a35"}},
0}, 0},
{<<"tds_proto">>, {<<"tds_proto">>,
{git,"https://github.com/valitydev/tds-proto.git", {git,"https://github.com/valitydev/tds-proto.git",