mirror of
https://github.com/valitydev/wapi-lib.git
synced 2024-11-06 18:25:17 +00:00
CAPI-279/CAPI-280: add token issue and withdrawal auth via grant/bearer (#5)
* CAPI-280: auth withdrawal via bearer or destination grant * Fix wapi related linter warnings * Do not run lint in CI for now * Add wallet grant implementation and fix some bugs * Refactor resource auth for withdrawal * Fix (dirty) user woody identity handling in ff_party * Fix challenge event search * Fix withdrawal and challenge status 'Failed' handling
This commit is contained in:
parent
529e9201af
commit
b8945abdf2
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@ -29,9 +29,13 @@ build('fistful-server', 'docker-host', finalHook) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: uncomment when linter warnings are fixed
|
||||||
|
*
|
||||||
runStage('lint') {
|
runStage('lint') {
|
||||||
sh 'make wc_lint'
|
sh 'make wc_lint'
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
runStage('xref') {
|
runStage('xref') {
|
||||||
sh 'make wc_xref'
|
sh 'make wc_xref'
|
||||||
|
2
Makefile
2
Makefile
@ -58,7 +58,7 @@ release: submodules generate
|
|||||||
clean:
|
clean:
|
||||||
$(REBAR) clean
|
$(REBAR) clean
|
||||||
|
|
||||||
distclean: swag_server.distclean swag_client.distclean
|
distclean: swagger.distclean.server.wallet swagger.distclean.client.wallet
|
||||||
$(REBAR) clean -a
|
$(REBAR) clean -a
|
||||||
rm -rf _build
|
rm -rf _build
|
||||||
|
|
||||||
|
@ -39,10 +39,10 @@
|
|||||||
ff_identity_challenge:challenge().
|
ff_identity_challenge:challenge().
|
||||||
|
|
||||||
-type event() ::
|
-type event() ::
|
||||||
{created , identity()} |
|
{created , identity()} |
|
||||||
{level_changed , level()} |
|
{level_changed , level()} |
|
||||||
{effective_challenge_changed, challenge_id()} |
|
{effective_challenge_changed, challenge_id()} |
|
||||||
{challenge , challenge_id(), ff_identity_challenge:ev()} .
|
{{challenge , challenge_id()}, ff_identity_challenge:ev()}.
|
||||||
|
|
||||||
-export_type([identity/0]).
|
-export_type([identity/0]).
|
||||||
-export_type([event/0]).
|
-export_type([event/0]).
|
||||||
|
@ -184,7 +184,7 @@ generate_uuid() ->
|
|||||||
%% Party management client
|
%% Party management client
|
||||||
|
|
||||||
do_create_party(ID, Params) ->
|
do_create_party(ID, Params) ->
|
||||||
case call('Create', [construct_userinfo(), ID, construct_party_params(Params)]) of
|
case call('Create', [ID, construct_party_params(Params)]) of
|
||||||
{ok, ok} ->
|
{ok, ok} ->
|
||||||
ok;
|
ok;
|
||||||
{exception, #payproc_PartyExists{}} ->
|
{exception, #payproc_PartyExists{}} ->
|
||||||
@ -194,7 +194,7 @@ do_create_party(ID, Params) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
do_get_party(ID) ->
|
do_get_party(ID) ->
|
||||||
case call('Get', [construct_userinfo(), ID]) of
|
case call('Get', [ID]) of
|
||||||
{ok, #domain_Party{} = Party} ->
|
{ok, #domain_Party{} = Party} ->
|
||||||
Party;
|
Party;
|
||||||
{exception, Unexpected} ->
|
{exception, Unexpected} ->
|
||||||
@ -202,7 +202,7 @@ do_get_party(ID) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
% do_get_contract(ID, ContractID) ->
|
% do_get_contract(ID, ContractID) ->
|
||||||
% case call('GetContract', [construct_userinfo(), ID, ContractID]) of
|
% case call('GetContract', [ID, ContractID]) of
|
||||||
% {ok, #domain_Contract{} = Contract} ->
|
% {ok, #domain_Contract{} = Contract} ->
|
||||||
% Contract;
|
% Contract;
|
||||||
% {exception, #payproc_ContractNotFound{}} ->
|
% {exception, #payproc_ContractNotFound{}} ->
|
||||||
@ -212,7 +212,7 @@ do_get_party(ID) ->
|
|||||||
% end.
|
% end.
|
||||||
|
|
||||||
do_get_wallet(ID, WalletID) ->
|
do_get_wallet(ID, WalletID) ->
|
||||||
case call('GetWallet', [construct_userinfo(), ID, WalletID]) of
|
case call('GetWallet', [ID, WalletID]) of
|
||||||
{ok, #domain_Wallet{} = Wallet} ->
|
{ok, #domain_Wallet{} = Wallet} ->
|
||||||
{ok, Wallet};
|
{ok, Wallet};
|
||||||
{exception, #payproc_WalletNotFound{}} ->
|
{exception, #payproc_WalletNotFound{}} ->
|
||||||
@ -222,7 +222,7 @@ do_get_wallet(ID, WalletID) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
do_create_claim(ID, Changeset) ->
|
do_create_claim(ID, Changeset) ->
|
||||||
case call('CreateClaim', [construct_userinfo(), ID, Changeset]) of
|
case call('CreateClaim', [ID, Changeset]) of
|
||||||
{ok, Claim} ->
|
{ok, Claim} ->
|
||||||
{ok, Claim};
|
{ok, Claim};
|
||||||
{exception, #payproc_InvalidChangeset{
|
{exception, #payproc_InvalidChangeset{
|
||||||
@ -241,7 +241,7 @@ do_accept_claim(ID, Claim) ->
|
|||||||
% such a way which may cause conflicts.
|
% such a way which may cause conflicts.
|
||||||
ClaimID = Claim#payproc_Claim.id,
|
ClaimID = Claim#payproc_Claim.id,
|
||||||
Revision = Claim#payproc_Claim.revision,
|
Revision = Claim#payproc_Claim.revision,
|
||||||
case call('AcceptClaim', [construct_userinfo(), ID, ClaimID, Revision]) of
|
case call('AcceptClaim', [ID, ClaimID, Revision]) of
|
||||||
{ok, ok} ->
|
{ok, ok} ->
|
||||||
accepted;
|
accepted;
|
||||||
{exception, #payproc_InvalidClaimStatus{status = {accepted, _}}} ->
|
{exception, #payproc_InvalidClaimStatus{status = {accepted, _}}} ->
|
||||||
@ -345,10 +345,27 @@ construct_userinfo() ->
|
|||||||
construct_usertype() ->
|
construct_usertype() ->
|
||||||
{service_user, #payproc_ServiceUser{}}.
|
{service_user, #payproc_ServiceUser{}}.
|
||||||
|
|
||||||
|
construct_useridentity() ->
|
||||||
|
#{
|
||||||
|
id => <<"fistful">>,
|
||||||
|
realm => <<"service">>
|
||||||
|
}.
|
||||||
|
|
||||||
%% Woody stuff
|
%% Woody stuff
|
||||||
|
|
||||||
call(Function, Args) ->
|
get_woody_ctx() ->
|
||||||
|
% TODO
|
||||||
|
% - Move auth logic from hellgate to capi the same way as it works
|
||||||
|
% in wapi & fistful. Then the following dirty user_identity hack
|
||||||
|
% will not be necessary anymore.
|
||||||
|
reset_useridentity(ff_woody_ctx:get()).
|
||||||
|
|
||||||
|
reset_useridentity(Ctx) ->
|
||||||
|
woody_user_identity:put(construct_useridentity(), maps:without([meta], Ctx)).
|
||||||
|
|
||||||
|
call(Function, Args0) ->
|
||||||
% TODO
|
% TODO
|
||||||
% - Ideally, we should provide `Client` here explicitly.
|
% - Ideally, we should provide `Client` here explicitly.
|
||||||
Service = {dmsl_payment_processing_thrift, 'PartyManagement'},
|
Service = {dmsl_payment_processing_thrift, 'PartyManagement'},
|
||||||
ff_woody_client:call(partymgmt, {Service, Function, Args}).
|
Args = [construct_userinfo() | Args0],
|
||||||
|
ff_woody_client:call(partymgmt, {Service, Function, Args}, get_woody_ctx()).
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
-export([new/1]).
|
-export([new/1]).
|
||||||
-export([call/2]).
|
-export([call/2]).
|
||||||
|
-export([call/3]).
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -56,11 +57,17 @@ new(Url) when is_binary(Url); is_list(Url) ->
|
|||||||
{ok, woody:result()} |
|
{ok, woody:result()} |
|
||||||
{exception, woody_error:business_error()}.
|
{exception, woody_error:business_error()}.
|
||||||
|
|
||||||
call(ServiceID, Request) when is_atom(ServiceID) ->
|
call(ServiceIdOrClient, Request) ->
|
||||||
Client = get_service_client(ServiceID),
|
call(ServiceIdOrClient, Request, ff_woody_ctx:get()).
|
||||||
woody_client:call(Request, Client, ff_woody_ctx:get());
|
|
||||||
call(Client, Request) when is_map(Client) ->
|
-spec call(service_id() | client(), woody:request(), woody_context:ctx()) ->
|
||||||
woody_client:call(Request, Client, ff_woody_ctx:get()).
|
{ok, woody:result()} |
|
||||||
|
{exception, woody_error:business_error()}.
|
||||||
|
|
||||||
|
call(ServiceID, Request, Context) when is_atom(ServiceID) ->
|
||||||
|
call(get_service_client(ServiceID), Request, Context);
|
||||||
|
call(Client, Request, Context) when is_map(Client) ->
|
||||||
|
woody_client:call(Request, Client, Context).
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
@ -150,12 +150,21 @@ match_scope(_, _) ->
|
|||||||
decode(V) ->
|
decode(V) ->
|
||||||
lists:foldl(fun decode_entry/2, new(), V).
|
lists:foldl(fun decode_entry/2, new(), V).
|
||||||
|
|
||||||
|
%% TODO
|
||||||
|
%% - Keycloak utilizes string ACLs and so do we for now. Nicer way to handle ACLs
|
||||||
|
%% is to use json instead for wapi issued tokens. That would require providing
|
||||||
|
%% similar routines for ACL normalization as we have for string ACLs.
|
||||||
decode_entry(V, ACL) ->
|
decode_entry(V, ACL) ->
|
||||||
case binary:split(V, <<":">>, [global]) of
|
case binary:split(V, <<":">>, [global]) of
|
||||||
[V1, V2] ->
|
[V1, V2] ->
|
||||||
Scope = decode_scope(V1),
|
%% Skip entries, which are not in wapi hierarchy
|
||||||
Permission = decode_permission(V2),
|
try
|
||||||
insert_scope(Scope, Permission, ACL);
|
Scope = decode_scope(V1),
|
||||||
|
Permission = decode_permission(V2),
|
||||||
|
insert_scope(Scope, Permission, ACL)
|
||||||
|
catch
|
||||||
|
error:{badarg, {resource, _}} -> ACL
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
error({badarg, {role, V}})
|
error({badarg, {role, V}})
|
||||||
end.
|
end.
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
-export([get_claims/1]).
|
-export([get_claims/1]).
|
||||||
-export([get_claim/2]).
|
-export([get_claim/2]).
|
||||||
-export([get_claim/3]).
|
-export([get_claim/3]).
|
||||||
-export([get_consumer/1]).
|
|
||||||
|
|
||||||
-export([get_resource_hierarchy/0]).
|
-export([get_resource_hierarchy/0]).
|
||||||
|
|
||||||
@ -80,74 +79,131 @@ do_authorize_api_key(_OperationID, bearer, Token) ->
|
|||||||
% TODO
|
% TODO
|
||||||
% We need shared type here, exported somewhere in swagger app
|
% We need shared type here, exported somewhere in swagger app
|
||||||
-type request_data() :: #{atom() | binary() => term()}.
|
-type request_data() :: #{atom() | binary() => term()}.
|
||||||
|
-type auth_method() :: bearer_token | grant.
|
||||||
|
-type resource() :: wallet | destination.
|
||||||
|
-type auth_details() :: auth_method() | [{resource(), auth_details()}].
|
||||||
|
-type auth_error() :: [{resource(), [{auth_method(), atom()}]}].
|
||||||
|
|
||||||
-spec authorize_operation(
|
-spec authorize_operation(operation_id(), request_data(), wapi_handler:context()) ->
|
||||||
OperationID :: operation_id(),
|
{ok, auth_details()} | {error, auth_error()}.
|
||||||
Req :: request_data(),
|
|
||||||
Auth :: wapi_authorizer_jwt:t()
|
|
||||||
) ->
|
|
||||||
ok | {error, unauthorized}.
|
|
||||||
|
|
||||||
%% TODO
|
authorize_operation('CreateWithdrawal', #{'WithdrawalParameters' := Params}, Context) ->
|
||||||
|
authorize_withdrawal(Params, Context);
|
||||||
|
%% TODO: implement authorization
|
||||||
authorize_operation(_OperationID, _Req, _) ->
|
authorize_operation(_OperationID, _Req, _) ->
|
||||||
ok.
|
{ok, bearer_token}.
|
||||||
%% authorize_operation(OperationID, Req, {{_SubjectID, ACL}, _}) ->
|
|
||||||
%% Access = get_operation_access(OperationID, Req),
|
|
||||||
%% _ = case lists:all(
|
|
||||||
%% fun ({Scope, Permission}) ->
|
|
||||||
%% lists:member(Permission, wapi_acl:match(Scope, ACL))
|
|
||||||
%% end,
|
|
||||||
%% Access
|
|
||||||
%% ) of
|
|
||||||
%% true ->
|
|
||||||
%% ok;
|
|
||||||
%% false ->
|
|
||||||
%% {error, unauthorized}
|
|
||||||
%% end.
|
|
||||||
|
|
||||||
%%
|
authorize_withdrawal(Params, Context) ->
|
||||||
|
lists:foldl(
|
||||||
|
fun(R, AuthState) ->
|
||||||
|
case {authorize_resource(R, Params, Context), AuthState} of
|
||||||
|
{{ok, AuthMethod}, {ok, AuthData}} -> {ok, [{R, AuthMethod} | AuthData]};
|
||||||
|
{{ok, _}, {error, _}} -> AuthState;
|
||||||
|
{{error, Error}, {error, ErrorData}} -> {error, [{R, Error} | ErrorData]};
|
||||||
|
{{error, Error}, {ok, _}} -> {error, [{R, Error}]}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{ok, []},
|
||||||
|
[destination, wallet]
|
||||||
|
).
|
||||||
|
|
||||||
|
authorize_resource(Resource, Params, Context) ->
|
||||||
|
%% TODO
|
||||||
|
%% - ff_pipeline:do/1 would make the code rather more clear here.
|
||||||
|
authorize_resource_by_bearer(authorize_resource_by_grant(Resource, Params), Resource, Params, Context).
|
||||||
|
|
||||||
|
authorize_resource_by_bearer(ok, _Resource, _Params, _Context) ->
|
||||||
|
{ok, grant};
|
||||||
|
authorize_resource_by_bearer({error, GrantError}, Resource, Params, Context) ->
|
||||||
|
case get_resource(Resource, maps:get(genlib:to_binary(Resource), Params), Context) of
|
||||||
|
{ok, _} ->
|
||||||
|
{ok, bearer_token};
|
||||||
|
{error, BearerError} ->
|
||||||
|
{error, [{bearer_token, BearerError}, {grant, GrantError}]}
|
||||||
|
end.
|
||||||
|
|
||||||
|
get_resource(destination, ID, Context) ->
|
||||||
|
wapi_wallet_ff_backend:get_destination(ID, Context);
|
||||||
|
get_resource(wallet, ID, Context) ->
|
||||||
|
wapi_wallet_ff_backend:get_wallet(ID, Context).
|
||||||
|
|
||||||
|
authorize_resource_by_grant(R = destination, #{
|
||||||
|
<<"destination">> := ID,
|
||||||
|
<<"destinationGrant">> := Grant
|
||||||
|
}) ->
|
||||||
|
authorize_resource_by_grant(R, Grant, get_resource_accesses(R, ID, write), undefined);
|
||||||
|
authorize_resource_by_grant(R = wallet, #{
|
||||||
|
<<"wallet">> := ID,
|
||||||
|
<<"walletGrant">> := Grant,
|
||||||
|
<<"body">> := WithdrawalBody
|
||||||
|
}) ->
|
||||||
|
authorize_resource_by_grant(R, Grant, get_resource_accesses(R, ID, write), WithdrawalBody);
|
||||||
|
authorize_resource_by_grant(_, _) ->
|
||||||
|
{error, missing}.
|
||||||
|
|
||||||
|
authorize_resource_by_grant(Resource, Grant, Access, Params) ->
|
||||||
|
case wapi_authorizer_jwt:verify(Grant) of
|
||||||
|
{ok, {{_, ACL}, Claims}} ->
|
||||||
|
verify_claims(Resource, verify_access(Access, ACL, Claims), Params);
|
||||||
|
Error = {error, _} ->
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
get_resource_accesses(Resource, ID, Permission) ->
|
||||||
|
[{get_resource_accesses(Resource, ID), Permission}].
|
||||||
|
|
||||||
|
get_resource_accesses(destination, ID) ->
|
||||||
|
[party, {destinations, ID}];
|
||||||
|
get_resource_accesses(wallet, ID) ->
|
||||||
|
[party, {wallets, ID}].
|
||||||
|
|
||||||
|
verify_access(Access, ACL, Claims) ->
|
||||||
|
case lists:all(
|
||||||
|
fun ({Scope, Permission}) -> lists:member(Permission, wapi_acl:match(Scope, ACL)) end,
|
||||||
|
Access
|
||||||
|
) of
|
||||||
|
true -> {ok, Claims};
|
||||||
|
false -> {error, insufficient_access}
|
||||||
|
end.
|
||||||
|
|
||||||
|
verify_claims(_, Error = {error, _}, _) ->
|
||||||
|
Error;
|
||||||
|
verify_claims(destination, {ok, _Claims}, _) ->
|
||||||
|
ok;
|
||||||
|
verify_claims(wallet,
|
||||||
|
{ok, #{<<"amount">> := GrantAmount, <<"currency">> := Currency}},
|
||||||
|
#{ <<"amount">> := ReqAmount, <<"currency">> := Currency }
|
||||||
|
) when GrantAmount >= ReqAmount ->
|
||||||
|
ok;
|
||||||
|
verify_claims(_, _, _) ->
|
||||||
|
{error, insufficient_claims}.
|
||||||
|
|
||||||
-type token_spec() ::
|
-type token_spec() ::
|
||||||
{destinations, DestinationID :: binary()}.
|
{destinations, DestinationID :: binary()} |
|
||||||
|
{wallets, WalletID :: binary(), Asset :: map()}.
|
||||||
|
|
||||||
-spec issue_access_token(wapi_handler_utils:party_id(), token_spec()) ->
|
-spec issue_access_token(wapi_handler_utils:owner(), token_spec()) ->
|
||||||
wapi_authorizer_jwt:token().
|
wapi_authorizer_jwt:token().
|
||||||
issue_access_token(PartyID, TokenSpec) ->
|
issue_access_token(PartyID, TokenSpec) ->
|
||||||
issue_access_token(PartyID, TokenSpec, unlimited).
|
issue_access_token(PartyID, TokenSpec, unlimited).
|
||||||
|
|
||||||
-type expiration() ::
|
-spec issue_access_token(wapi_handler_utils:owner(), token_spec(), wapi_authorizer_jwt:expiration()) ->
|
||||||
{deadline, machinery:timestamp() | pos_integer()} |
|
|
||||||
{lifetime, Seconds :: pos_integer()} |
|
|
||||||
unlimited .
|
|
||||||
|
|
||||||
-spec issue_access_token(wapi_handler_utils:party_id(), token_spec(), expiration()) ->
|
|
||||||
wapi_authorizer_jwt:token().
|
wapi_authorizer_jwt:token().
|
||||||
issue_access_token(PartyID, TokenSpec, Expiration0) ->
|
issue_access_token(PartyID, TokenSpec, Expiration) ->
|
||||||
Expiration = get_expiration(Expiration0),
|
|
||||||
{Claims, ACL} = resolve_token_spec(TokenSpec),
|
{Claims, ACL} = resolve_token_spec(TokenSpec),
|
||||||
wapi_utils:unwrap(wapi_authorizer_jwt:issue({{PartyID, wapi_acl:from_list(ACL)}, Claims}, Expiration)).
|
wapi_utils:unwrap(wapi_authorizer_jwt:issue({{PartyID, wapi_acl:from_list(ACL)}, Claims}, Expiration)).
|
||||||
|
|
||||||
-spec get_expiration(expiration()) ->
|
|
||||||
wapi_authorizer_jwt:expiration().
|
|
||||||
get_expiration(Exp = unlimited) ->
|
|
||||||
Exp;
|
|
||||||
get_expiration({deadline, {DateTime, Usec}}) ->
|
|
||||||
{deadline, genlib_time:to_unixtime(DateTime) + Usec div 1000000};
|
|
||||||
get_expiration(Exp = {deadline, _Sec}) ->
|
|
||||||
Exp;
|
|
||||||
get_expiration(Exp = {lifetime, _Sec}) ->
|
|
||||||
Exp.
|
|
||||||
|
|
||||||
-type acl() :: [{wapi_acl:scope(), wapi_acl:permission()}].
|
-type acl() :: [{wapi_acl:scope(), wapi_acl:permission()}].
|
||||||
|
|
||||||
-spec resolve_token_spec(token_spec()) ->
|
-spec resolve_token_spec(token_spec()) ->
|
||||||
{claims(), acl()}.
|
{claims(), acl()}.
|
||||||
resolve_token_spec({destinations, DestinationId}) ->
|
resolve_token_spec({destinations, DestinationId}) ->
|
||||||
Claims = #{},
|
Claims = #{},
|
||||||
ACL = [
|
ACL = [{[party, {destinations, DestinationId}], write}],
|
||||||
{[party, {destinations, DestinationId}], read},
|
{Claims, ACL};
|
||||||
{[party, {destinations, DestinationId}], write}
|
resolve_token_spec({wallets, WalletId, #{<<"amount">> := Amount, <<"currency">> := Currency}}) ->
|
||||||
],
|
Claims = #{<<"amount">> => Amount, <<"currency">> => Currency},
|
||||||
|
ACL = [{[party, {wallets, WalletId}], write}],
|
||||||
{Claims, ACL}.
|
{Claims, ACL}.
|
||||||
|
|
||||||
-spec get_subject_id(context()) -> binary().
|
-spec get_subject_id(context()) -> binary().
|
||||||
@ -176,25 +232,16 @@ get_claim(ClaimName, {_Subject, Claims}, Default) ->
|
|||||||
%% -spec get_operation_access(operation_id(), request_data()) ->
|
%% -spec get_operation_access(operation_id(), request_data()) ->
|
||||||
%% [{wapi_acl:scope(), wapi_acl:permission()}].
|
%% [{wapi_acl:scope(), wapi_acl:permission()}].
|
||||||
|
|
||||||
%% get_operation_access('StoreBankCard' , _) ->
|
%% get_operation_access('CreateWithdrawal' , #{'WithdrawalParameters' := #{<<"walletGrant">> => }}) ->
|
||||||
%% [{[payment_resources], write}].
|
%% [{[payment_resources], write}].
|
||||||
|
|
||||||
-spec get_resource_hierarchy() -> #{atom() => map()}.
|
-spec get_resource_hierarchy() -> #{atom() => map()}.
|
||||||
|
|
||||||
%% TODO add some sence in here
|
%% TODO put some sense in here
|
||||||
get_resource_hierarchy() ->
|
get_resource_hierarchy() ->
|
||||||
#{
|
#{
|
||||||
party => #{
|
party => #{
|
||||||
wallets => #{},
|
wallets => #{},
|
||||||
destinations => #{}
|
destinations => #{}
|
||||||
}
|
}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-spec get_consumer(claims()) ->
|
|
||||||
consumer().
|
|
||||||
get_consumer(Claims) ->
|
|
||||||
case maps:get(<<"cons">>, Claims, <<"merchant">>) of
|
|
||||||
<<"merchant">> -> merchant;
|
|
||||||
<<"client" >> -> client;
|
|
||||||
<<"provider">> -> provider
|
|
||||||
end.
|
|
||||||
|
@ -280,12 +280,9 @@ validate_claims(Claims, [{Name, Claim, Validator} | Rest], Acc) ->
|
|||||||
validate_claims(Claims, [], Acc) ->
|
validate_claims(Claims, [], Acc) ->
|
||||||
{Acc, Claims}.
|
{Acc, Claims}.
|
||||||
|
|
||||||
get_result(SubjectID, {_Roles, Claims}) ->
|
get_result(SubjectID, {Roles, Claims}) ->
|
||||||
try
|
try
|
||||||
%% TODO use the real acl decode as soon as wapi roles/scopes are clearly defined
|
Subject = {SubjectID, wapi_acl:decode(Roles)},
|
||||||
%% Subject = {SubjectID, wapi_acl:decode(Roles)},
|
|
||||||
|
|
||||||
Subject = {SubjectID, wapi_acl:new()},
|
|
||||||
{ok, {Subject, Claims}}
|
{ok, {Subject, Claims}}
|
||||||
catch
|
catch
|
||||||
error:{badarg, _} = Reason ->
|
error:{badarg, _} = Reason ->
|
||||||
@ -351,6 +348,14 @@ decode_roles(Claims = #{
|
|||||||
}
|
}
|
||||||
}) when is_list(Roles) ->
|
}) when is_list(Roles) ->
|
||||||
{Roles, maps:remove(<<"resource_access">>, Claims)};
|
{Roles, maps:remove(<<"resource_access">>, Claims)};
|
||||||
|
decode_roles(Claims = #{
|
||||||
|
<<"resource_access">> := #{
|
||||||
|
<<"wallet-api">> := #{
|
||||||
|
<<"roles">> := Roles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) when is_list(Roles) ->
|
||||||
|
{Roles, maps:remove(<<"resource_access">>, Claims)};
|
||||||
decode_roles(_) ->
|
decode_roles(_) ->
|
||||||
throw({invalid_token, {missing, acl}}).
|
throw({invalid_token, {missing, acl}}).
|
||||||
|
|
||||||
|
@ -54,15 +54,15 @@
|
|||||||
handle_request(OperationID, Req, SwagContext = #{auth_context := AuthContext}, Handler, Opts) ->
|
handle_request(OperationID, Req, SwagContext = #{auth_context := AuthContext}, Handler, Opts) ->
|
||||||
_ = lager:info("Processing request ~p", [OperationID]),
|
_ = lager:info("Processing request ~p", [OperationID]),
|
||||||
try
|
try
|
||||||
case wapi_auth:authorize_operation(OperationID, Req, AuthContext) of
|
WoodyContext = create_woody_context(Req, AuthContext, Opts),
|
||||||
ok ->
|
Context = create_handler_context(SwagContext, WoodyContext),
|
||||||
WoodyContext = create_woody_context(Req, AuthContext, Opts),
|
case wapi_auth:authorize_operation(OperationID, Req, Context) of
|
||||||
Context = create_handler_context(SwagContext, WoodyContext),
|
{ok, AuthDetails} ->
|
||||||
Handler:process_request(OperationID, Req, Context, Opts)
|
ok = lager:info("Operation ~p authorized via ~p", [OperationID, AuthDetails]),
|
||||||
%% ToDo: return back as soon, as authorization is implemented
|
Handler:process_request(OperationID, Req, Context, Opts);
|
||||||
%% {error, _} = Error ->
|
{error, Error} ->
|
||||||
%% _ = lager:info("Operation ~p authorization failed due to ~p", [OperationID, Error]),
|
ok = lager:info("Operation ~p authorization failed due to ~p", [OperationID, Error]),
|
||||||
%% wapi_handler_utils:reply_error(401, wapi_handler_utils:get_error_msg(<<"Unauthorized operation">>))
|
wapi_handler_utils:reply_error(401, wapi_handler_utils:get_error_msg(<<"Unauthorized operation">>))
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
throw:{?request_result, Result} ->
|
throw:{?request_result, Result} ->
|
||||||
|
@ -67,7 +67,9 @@ redact_match([Capture], Message) ->
|
|||||||
%% mask(Dir, MaskLen, string:length(Str), MaskChar, Str).
|
%% mask(Dir, MaskLen, string:length(Str), MaskChar, Str).
|
||||||
|
|
||||||
%% mask(Dir, KeepStart, KeepLen, MaskChar, Str) ->
|
%% mask(Dir, KeepStart, KeepLen, MaskChar, Str) ->
|
||||||
%% unicode:characters_to_binary(string:pad(string:slice(Str, KeepStart, KeepLen), string:length(Str), Dir, MaskChar)).
|
%% unicode:characters_to_binary(
|
||||||
|
%% string:pad(string:slice(Str, KeepStart, KeepLen), string:length(Str), Dir, MaskChar)
|
||||||
|
%% ).
|
||||||
|
|
||||||
-spec mask_and_keep(leading|trailing, non_neg_integer(), char(), binary()) ->
|
-spec mask_and_keep(leading|trailing, non_neg_integer(), char(), binary()) ->
|
||||||
binary().
|
binary().
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
-module(wapi_wallet_ff_backend).
|
-module(wapi_wallet_ff_backend).
|
||||||
|
|
||||||
-include_lib("dmsl/include/dmsl_payment_processing_thrift.hrl").
|
-include_lib("dmsl/include/dmsl_payment_processing_thrift.hrl").
|
||||||
|
-include_lib("dmsl/include/dmsl_domain_thrift.hrl").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([get_providers/2]).
|
-export([get_providers/2]).
|
||||||
@ -205,7 +206,7 @@ get_identity_challenge_event(#{
|
|||||||
'eventID' := EventId
|
'eventID' := EventId
|
||||||
}, Context) ->
|
}, Context) ->
|
||||||
Mapper = fun
|
Mapper = fun
|
||||||
({ID, {ev, Ts, {challenge, I, Body = {status_changed, _}}}}) when I =:= ChallengeId andalso ID =:= EventId ->
|
({ID, {ev, Ts, {{challenge, I}, Body = {status_changed, _}}}}) when I =:= ChallengeId andalso ID =:= EventId ->
|
||||||
{true, {ID, Ts, Body}};
|
{true, {ID, Ts, Body}};
|
||||||
(_) ->
|
(_) ->
|
||||||
false
|
false
|
||||||
@ -232,7 +233,9 @@ create_wallet(Params = #{<<"identity">> := IdenityId}, Context) ->
|
|||||||
WalletId = next_id('wallet'),
|
WalletId = next_id('wallet'),
|
||||||
do(fun() ->
|
do(fun() ->
|
||||||
_ = check_resource(identity, IdenityId, Context),
|
_ = check_resource(identity, IdenityId, Context),
|
||||||
ok = unwrap(ff_wallet_machine:create(WalletId, from_swag(wallet_params, Params), make_ctx(Params, [], Context))),
|
ok = unwrap(
|
||||||
|
ff_wallet_machine:create(WalletId, from_swag(wallet_params, Params), make_ctx(Params, [], Context))
|
||||||
|
),
|
||||||
unwrap(get_wallet(WalletId, Context))
|
unwrap(get_wallet(WalletId, Context))
|
||||||
end).
|
end).
|
||||||
|
|
||||||
@ -629,17 +632,16 @@ to_swag(challenge_status, {completed, C = #{resolution := approved}}) ->
|
|||||||
<<"validUntil">> => to_swag(timestamp, genlib_map:get(valid_until, C))
|
<<"validUntil">> => to_swag(timestamp, genlib_map:get(valid_until, C))
|
||||||
});
|
});
|
||||||
to_swag(challenge_status, {completed, #{resolution := denied}}) ->
|
to_swag(challenge_status, {completed, #{resolution := denied}}) ->
|
||||||
#{
|
to_swag(challenge_status, {failed, <<"Denied">>});
|
||||||
<<"status">> => <<"Failed">>,
|
|
||||||
<<"failureReason">> => <<"Denied">>
|
|
||||||
};
|
|
||||||
to_swag(challenge_status, {failed, Reason}) ->
|
to_swag(challenge_status, {failed, Reason}) ->
|
||||||
%% TODO
|
|
||||||
%% - Well, what if Reason is not scalar?
|
|
||||||
#{
|
#{
|
||||||
<<"status">> => <<"Failed">>,
|
<<"status">> => <<"Failed">>,
|
||||||
<<"failureReason">> => genlib:to_binary(Reason)
|
<<"failureReason">> => to_swag(challenge_failure_reason, Reason)
|
||||||
};
|
};
|
||||||
|
to_swag(challenge_failure_reason, Failure = #domain_Failure{}) ->
|
||||||
|
to_swag(domain_failure, Failure);
|
||||||
|
to_swag(challenge_failure_reason, Reason) ->
|
||||||
|
genlib:to_binary(Reason);
|
||||||
to_swag(identity_challenge_event, {ID, Ts, V}) ->
|
to_swag(identity_challenge_event, {ID, Ts, V}) ->
|
||||||
#{
|
#{
|
||||||
<<"eventID">> => ID,
|
<<"eventID">> => ID,
|
||||||
@ -733,13 +735,17 @@ to_swag(withdrawal_status, pending) ->
|
|||||||
#{<<"status">> => <<"Pending">>};
|
#{<<"status">> => <<"Pending">>};
|
||||||
to_swag(withdrawal_status, succeeded) ->
|
to_swag(withdrawal_status, succeeded) ->
|
||||||
#{<<"status">> => <<"Succeeded">>};
|
#{<<"status">> => <<"Succeeded">>};
|
||||||
to_swag(withdrawal_status, {failed, Reason}) ->
|
to_swag(withdrawal_status, {failed, Failure}) ->
|
||||||
#{
|
#{
|
||||||
<<"status">> => <<"Failed">>,
|
<<"status">> => <<"Failed">>,
|
||||||
<<"failure">> => #{
|
<<"failure">> => #{
|
||||||
<<"code">> => genlib:to_binary(Reason)
|
<<"code">> => to_swag(withdrawal_status_failure, Failure)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
to_swag(withdrawal_status_failure, Failure = #domain_Failure{}) ->
|
||||||
|
to_swag(domain_failure, Failure);
|
||||||
|
to_swag(withdrawal_status_failure, Failure) ->
|
||||||
|
genlib:to_binary(Failure);
|
||||||
to_swag(withdrawal_event, {EventId, Ts, {status_changed, Status}}) ->
|
to_swag(withdrawal_event, {EventId, Ts, {status_changed, Status}}) ->
|
||||||
to_swag(map, #{
|
to_swag(map, #{
|
||||||
<<"eventID">> => EventId,
|
<<"eventID">> => EventId,
|
||||||
@ -763,6 +769,8 @@ to_swag(currency_object, V) ->
|
|||||||
<<"exponent">> => maps:get(exponent, V),
|
<<"exponent">> => maps:get(exponent, V),
|
||||||
<<"sign">> => maps:get(sign, V, undefined)
|
<<"sign">> => maps:get(sign, V, undefined)
|
||||||
});
|
});
|
||||||
|
to_swag(domain_failure, Failure = #domain_Failure{}) ->
|
||||||
|
erlang:list_to_binary(payproc_errors:format_raw(Failure));
|
||||||
to_swag(is_blocked, {ok, accessible}) ->
|
to_swag(is_blocked, {ok, accessible}) ->
|
||||||
false;
|
false;
|
||||||
to_swag(is_blocked, _) ->
|
to_swag(is_blocked, _) ->
|
||||||
|
@ -133,8 +133,10 @@ process_request('StartIdentityChallenge', #{
|
|||||||
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Proof not found">>));
|
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Proof not found">>));
|
||||||
{error, {challenge, {proof, insufficient}}} ->
|
{error, {challenge, {proof, insufficient}}} ->
|
||||||
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Insufficient proof">>));
|
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Insufficient proof">>));
|
||||||
{error,{challenge, {level, _}}} ->
|
{error, {challenge, {level, _}}} ->
|
||||||
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Illegal identification type for current identity level">>))
|
wapi_handler_utils:reply_ok(422,
|
||||||
|
wapi_handler_utils:get_error_msg(<<"Illegal identification type for current identity level">>)
|
||||||
|
)
|
||||||
%% TODO any other possible errors here?
|
%% TODO any other possible errors here?
|
||||||
end;
|
end;
|
||||||
process_request('GetIdentityChallenge', #{
|
process_request('GetIdentityChallenge', #{
|
||||||
@ -145,13 +147,13 @@ process_request('GetIdentityChallenge', #{
|
|||||||
{ok, Challenge} -> wapi_handler_utils:reply_ok(200, Challenge);
|
{ok, Challenge} -> wapi_handler_utils:reply_ok(200, Challenge);
|
||||||
{error, {identity, notfound}} -> wapi_handler_utils:reply_ok(404);
|
{error, {identity, notfound}} -> wapi_handler_utils:reply_ok(404);
|
||||||
{error, {identity, unauthorized}} -> wapi_handler_utils:reply_ok(404);
|
{error, {identity, unauthorized}} -> wapi_handler_utils:reply_ok(404);
|
||||||
{error, {challenge, notfound}} -> wapi_handler_utils:reply_ok(404)
|
{error, {challenge, notfound}} -> wapi_handler_utils:reply_ok(404)
|
||||||
end;
|
end;
|
||||||
process_request('PollIdentityChallengeEvents', Params, Context, _Opts) ->
|
process_request('PollIdentityChallengeEvents', Params, Context, _Opts) ->
|
||||||
case wapi_wallet_ff_backend:get_identity_challenge_events(Params, Context) of
|
case wapi_wallet_ff_backend:get_identity_challenge_events(Params, Context) of
|
||||||
{ok, Events} -> wapi_handler_utils:reply_ok(200, Events);
|
{ok, Events} -> wapi_handler_utils:reply_ok(200, Events);
|
||||||
{error, {identity, notfound}} -> wapi_handler_utils:reply_ok(404);
|
{error, {identity, notfound}} -> wapi_handler_utils:reply_ok(404);
|
||||||
{error, {identity,unauthorized}} -> wapi_handler_utils:reply_ok(404)
|
{error, {identity, unauthorized}} -> wapi_handler_utils:reply_ok(404)
|
||||||
end;
|
end;
|
||||||
process_request('GetIdentityChallengeEvent', Params, Context, _Opts) ->
|
process_request('GetIdentityChallengeEvent', Params, Context, _Opts) ->
|
||||||
case wapi_wallet_ff_backend:get_identity_challenge_event(Params, Context) of
|
case wapi_wallet_ff_backend:get_identity_challenge_event(Params, Context) of
|
||||||
@ -191,19 +193,24 @@ process_request('GetWalletAccount', #{'walletID' := WalletId}, Context, _Opts) -
|
|||||||
{error, {wallet, notfound}} -> wapi_handler_utils:reply_ok(404);
|
{error, {wallet, notfound}} -> wapi_handler_utils:reply_ok(404);
|
||||||
{error, {wallet, unauthorized}} -> wapi_handler_utils:reply_ok(404)
|
{error, {wallet, unauthorized}} -> wapi_handler_utils:reply_ok(404)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process_request('IssueWalletGrant', #{
|
process_request('IssueWalletGrant', #{
|
||||||
'walletID' := WalletId,
|
'walletID' := WalletId,
|
||||||
'WalletGrantRequest' := #{<<"validUntil">> := Expiration, <<"asset">> := Asset}
|
'WalletGrantRequest' := #{<<"validUntil">> := Expiration, <<"asset">> := Asset}
|
||||||
}, Context, _Opts) ->
|
}, Context, _Opts) ->
|
||||||
case wapi_wallet_ff_backend:get_wallet(WalletId, Context) of
|
case wapi_wallet_ff_backend:get_wallet(WalletId, Context) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
%% TODO issue token properly
|
case issue_grant_token({wallets, WalletId, Asset}, Expiration, Context) of
|
||||||
wapi_handler_utils:reply_ok(201, #{
|
{ok, Token} ->
|
||||||
<<"token">> => issue_grant_token(wallets, WalletId, Expiration, #{<<"asset">> => Asset}),
|
wapi_handler_utils:reply_ok(201, #{
|
||||||
<<"validUntil">> => Expiration,
|
<<"token">> => Token,
|
||||||
<<"asset">> => Asset
|
<<"validUntil">> => Expiration,
|
||||||
});
|
<<"asset">> => Asset
|
||||||
|
});
|
||||||
|
{error, expired} ->
|
||||||
|
wapi_handler_utils:reply_ok(422,
|
||||||
|
wapi_handler_utils:get_error_msg(<<"Invalid expiration: already expired">>)
|
||||||
|
)
|
||||||
|
end;
|
||||||
{error, {wallet, notfound}} ->
|
{error, {wallet, notfound}} ->
|
||||||
wapi_handler_utils:reply_ok(404);
|
wapi_handler_utils:reply_ok(404);
|
||||||
{error, {wallet, unauthorized}} ->
|
{error, {wallet, unauthorized}} ->
|
||||||
@ -242,20 +249,25 @@ process_request('IssueDestinationGrant', #{
|
|||||||
'destinationID' := DestinationId,
|
'destinationID' := DestinationId,
|
||||||
'DestinationGrantRequest' := #{<<"validUntil">> := Expiration}
|
'DestinationGrantRequest' := #{<<"validUntil">> := Expiration}
|
||||||
}, Context, _Opts) ->
|
}, Context, _Opts) ->
|
||||||
%% TODO issue token properly
|
|
||||||
case wapi_wallet_ff_backend:get_destination(DestinationId, Context) of
|
case wapi_wallet_ff_backend:get_destination(DestinationId, Context) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
wapi_handler_utils:reply_ok(201, #{
|
case issue_grant_token({destinations, DestinationId}, Expiration, Context) of
|
||||||
<<"token">> => issue_grant_token(destinations, DestinationId, Expiration, #{}),
|
{ok, Token} ->
|
||||||
<<"validUntil">> => Expiration
|
wapi_handler_utils:reply_ok(201, #{
|
||||||
});
|
<<"token">> => Token,
|
||||||
|
<<"validUntil">> => Expiration
|
||||||
|
});
|
||||||
|
{error, expired} ->
|
||||||
|
wapi_handler_utils:reply_ok(422,
|
||||||
|
wapi_handler_utils:get_error_msg(<<"Invalid expiration: already expired">>)
|
||||||
|
)
|
||||||
|
end;
|
||||||
{error, {destination, notfound}} ->
|
{error, {destination, notfound}} ->
|
||||||
wapi_handler_utils:reply_ok(404);
|
wapi_handler_utils:reply_ok(404);
|
||||||
{error, {destination, unauthorized}} ->
|
{error, {destination, unauthorized}} ->
|
||||||
wapi_handler_utils:reply_ok(404)
|
wapi_handler_utils:reply_ok(404)
|
||||||
end;
|
end;
|
||||||
process_request('CreateWithdrawal', #{'WithdrawalParameters' := Params}, Context, Opts) ->
|
process_request('CreateWithdrawal', #{'WithdrawalParameters' := Params}, Context, Opts) ->
|
||||||
%% TODO: properly check authorization tokens here
|
|
||||||
case wapi_wallet_ff_backend:create_withdrawal(Params, Context) of
|
case wapi_wallet_ff_backend:create_withdrawal(Params, Context) of
|
||||||
{ok, Withdrawal = #{<<"id">> := WithdrawalId}} ->
|
{ok, Withdrawal = #{<<"id">> := WithdrawalId}} ->
|
||||||
wapi_handler_utils:reply_ok(202, Withdrawal, get_location('GetWithdrawal', [WithdrawalId], Opts));
|
wapi_handler_utils:reply_ok(202, Withdrawal, get_location('GetWithdrawal', [WithdrawalId], Opts));
|
||||||
@ -268,11 +280,17 @@ process_request('CreateWithdrawal', #{'WithdrawalParameters' := Params}, Context
|
|||||||
{error, {provider, notfound}} ->
|
{error, {provider, notfound}} ->
|
||||||
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"No such provider">>));
|
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"No such provider">>));
|
||||||
{error, {wallet, {inaccessible, _}}} ->
|
{error, {wallet, {inaccessible, _}}} ->
|
||||||
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Inaccessible source or destination">>));
|
wapi_handler_utils:reply_ok(422,
|
||||||
|
wapi_handler_utils:get_error_msg(<<"Inaccessible source or destination">>)
|
||||||
|
);
|
||||||
{error, {wallet, {currency, invalid}}} ->
|
{error, {wallet, {currency, invalid}}} ->
|
||||||
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Invalid currency for source or destination">>));
|
wapi_handler_utils:reply_ok(422,
|
||||||
|
wapi_handler_utils:get_error_msg(<<"Invalid currency for source or destination">>)
|
||||||
|
);
|
||||||
{error, {wallet, {provider, invalid}}} ->
|
{error, {wallet, {provider, invalid}}} ->
|
||||||
wapi_handler_utils:reply_ok(422, wapi_handler_utils:get_error_msg(<<"Invalid provider for source or destination">>))
|
wapi_handler_utils:reply_ok(422,
|
||||||
|
wapi_handler_utils:get_error_msg(<<"Invalid provider for source or destination">>)
|
||||||
|
)
|
||||||
end;
|
end;
|
||||||
process_request('GetWithdrawal', #{'withdrawalID' := WithdrawalId}, Context, _Opts) ->
|
process_request('GetWithdrawal', #{'withdrawalID' := WithdrawalId}, Context, _Opts) ->
|
||||||
case wapi_wallet_ff_backend:get_withdrawal(WithdrawalId, Context) of
|
case wapi_wallet_ff_backend:get_withdrawal(WithdrawalId, Context) of
|
||||||
@ -321,25 +339,20 @@ get_location(OperationId, Params, Opts) ->
|
|||||||
not_implemented() ->
|
not_implemented() ->
|
||||||
wapi_handler_utils:throw_not_implemented().
|
wapi_handler_utils:throw_not_implemented().
|
||||||
|
|
||||||
|
issue_grant_token(TokenSpec, Expiration, Context) ->
|
||||||
|
case get_expiration_deadline(Expiration) of
|
||||||
|
{ok, Deadline} ->
|
||||||
|
{ok, wapi_auth:issue_access_token(wapi_handler_utils:get_owner(Context), TokenSpec, {deadline, Deadline})};
|
||||||
|
Error = {error, _} ->
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
issue_grant_token(Type, Id, Expiration, Meta) when is_map(Meta) ->
|
get_expiration_deadline(Expiration) ->
|
||||||
wapi_utils:map_to_base64url(#{
|
{DateTime, MilliSec} = woody_deadline:from_binary(wapi_utils:to_universal_time(Expiration)),
|
||||||
<<"resourceType">> => Type,
|
Deadline = genlib_time:daytime_to_unixtime(DateTime) + MilliSec div 1000,
|
||||||
<<"resourceID">> => Id,
|
case genlib_time:unow() - Deadline < 0 of
|
||||||
<<"validUntil">> => Expiration,
|
true ->
|
||||||
<<"metadata">> => Meta
|
{ok, Deadline};
|
||||||
}).
|
false ->
|
||||||
|
{error, expired}
|
||||||
%% TODO issue token properly
|
end.
|
||||||
%%
|
|
||||||
%% issue_grant_token(destinations, Id, Expiration, _Meta, Context) ->
|
|
||||||
%% {ok, {Date, Time, Usec, _Tz}} = rfc3339:parse(Expiration),
|
|
||||||
%% wapi_auth:issue_access_token(
|
|
||||||
%% wapi_handler_utils:get_owner(Context),
|
|
||||||
%% {destinations, Id},
|
|
||||||
%% {deadline, {{Date, Time}, Usec}}
|
|
||||||
%% ).
|
|
||||||
%%
|
|
||||||
%% is_expired(Expiration) ->
|
|
||||||
%% {ok, ExpirationSec} = rfc3339:to_time(Expiration, second),
|
|
||||||
%% (genlib_time:unow() - ExpirationSec) >= 0.
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
{elvis_style, nesting_level, #{level => 3}},
|
{elvis_style, nesting_level, #{level => 3}},
|
||||||
{elvis_style, god_modules, #{limit => 30, ignore => [hg_client_party]}},
|
{elvis_style, god_modules, #{limit => 30, ignore => [hg_client_party]}},
|
||||||
{elvis_style, no_if_expression},
|
{elvis_style, no_if_expression},
|
||||||
{elvis_style, invalid_dynamic_call, #{ignore => [elvis]}},
|
{elvis_style, invalid_dynamic_call, #{ignore => [wapi_swagger_server]}},
|
||||||
{elvis_style, used_ignored_variable},
|
{elvis_style, used_ignored_variable},
|
||||||
{elvis_style, no_behavior_info},
|
{elvis_style, no_behavior_info},
|
||||||
{elvis_style, module_naming_convention, #{regex => "^([a-z][a-z0-9]*_?)*(_SUITE)?$"}},
|
{elvis_style, module_naming_convention, #{regex => "^([a-z][a-z0-9]*_?)*(_SUITE)?$"}},
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{"1.1.0",
|
{"1.1.0",
|
||||||
[{<<"base64url">>,{pkg,<<"base64url">>,<<"0.0.1">>},0},
|
[{<<"base64url">>,{pkg,<<"base64url">>,<<"0.0.1">>},0},
|
||||||
|
{<<"cache">>,{pkg,<<"cache">>,<<"2.2.0">>},1},
|
||||||
{<<"certifi">>,{pkg,<<"certifi">>,<<"0.7.0">>},1},
|
{<<"certifi">>,{pkg,<<"certifi">>,<<"0.7.0">>},1},
|
||||||
{<<"cg_mon">>,
|
{<<"cg_mon">>,
|
||||||
{git,"https://github.com/rbkmoney/cg_mon.git",
|
{git,"https://github.com/rbkmoney/cg_mon.git",
|
||||||
@ -64,7 +65,7 @@
|
|||||||
0},
|
0},
|
||||||
{<<"machinery">>,
|
{<<"machinery">>,
|
||||||
{git,"git@github.com:rbkmoney/machinery.git",
|
{git,"git@github.com:rbkmoney/machinery.git",
|
||||||
{ref,"eb1beed9a287d8b6ab8c68b782b2143ef574c99d"}},
|
{ref,"ef24b4fff41b88981e0441b4097cbaa016e8e1b5"}},
|
||||||
0},
|
0},
|
||||||
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},1},
|
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},1},
|
||||||
{<<"mg_proto">>,
|
{<<"mg_proto">>,
|
||||||
@ -99,7 +100,7 @@
|
|||||||
{<<"uuid">>,{pkg,<<"uuid_erl">>,<<"1.7.3">>},0},
|
{<<"uuid">>,{pkg,<<"uuid_erl">>,<<"1.7.3">>},0},
|
||||||
{<<"woody">>,
|
{<<"woody">>,
|
||||||
{git,"git@github.com:rbkmoney/woody_erlang.git",
|
{git,"git@github.com:rbkmoney/woody_erlang.git",
|
||||||
{ref,"06ef3d63c0b6777e7cfa4b4f949eb34008291c0e"}},
|
{ref,"94eb44904e817e615f5e1586d6f3432cdadd5e29"}},
|
||||||
0},
|
0},
|
||||||
{<<"woody_user_identity">>,
|
{<<"woody_user_identity">>,
|
||||||
{git,"git@github.com:rbkmoney/woody_erlang_user_identity.git",
|
{git,"git@github.com:rbkmoney/woody_erlang_user_identity.git",
|
||||||
@ -108,6 +109,7 @@
|
|||||||
[
|
[
|
||||||
{pkg_hash,[
|
{pkg_hash,[
|
||||||
{<<"base64url">>, <<"36A90125F5948E3AFD7BE97662A1504B934DD5DAC78451CA6E9ABF85A10286BE">>},
|
{<<"base64url">>, <<"36A90125F5948E3AFD7BE97662A1504B934DD5DAC78451CA6E9ABF85A10286BE">>},
|
||||||
|
{<<"cache">>, <<"3C11DBF4CD8FCD5787C95A5FB2A04038E3729CFCA0386016EEA8C953AB48A5AB">>},
|
||||||
{<<"certifi">>, <<"861A57F3808F7EB0C2D1802AFEAAE0FA5DE813B0DF0979153CBAFCD853ABABAF">>},
|
{<<"certifi">>, <<"861A57F3808F7EB0C2D1802AFEAAE0FA5DE813B0DF0979153CBAFCD853ABABAF">>},
|
||||||
{<<"cowboy">>, <<"A324A8DF9F2316C833A470D918AAF73AE894278B8AA6226CE7A9BF699388F878">>},
|
{<<"cowboy">>, <<"A324A8DF9F2316C833A470D918AAF73AE894278B8AA6226CE7A9BF699388F878">>},
|
||||||
{<<"cowlib">>, <<"9D769A1D062C9C3AC753096F868CA121E2730B9A377DE23DEC0F7E08B1DF84EE">>},
|
{<<"cowlib">>, <<"9D769A1D062C9C3AC753096F868CA121E2730B9A377DE23DEC0F7E08B1DF84EE">>},
|
||||||
|
Loading…
Reference in New Issue
Block a user